mirror of
https://github.com/nim-lang/Nim.git
synced 2026-07-16 06:00:57 +00:00
Fix date parsing for a bad inputs
This commit is contained in:
@@ -936,24 +936,36 @@ proc parseToken(dt: var DateTime; token, value: string; j: var int) =
|
|||||||
var sv: int
|
var sv: int
|
||||||
case token
|
case token
|
||||||
of "d":
|
of "d":
|
||||||
var pd = parseInt(value[j..j+1], sv)
|
if value.len >= j+1:
|
||||||
dt.monthday = sv
|
var pd = parseInt(value[j..j+1], sv)
|
||||||
j += pd
|
dt.monthday = sv
|
||||||
of "dd":
|
j += pd
|
||||||
dt.monthday = value[j..j+1].parseInt()
|
|
||||||
j += 2
|
|
||||||
of "ddd":
|
|
||||||
case value[j..j+2].toLowerAscii()
|
|
||||||
of "sun": dt.weekday = dSun
|
|
||||||
of "mon": dt.weekday = dMon
|
|
||||||
of "tue": dt.weekday = dTue
|
|
||||||
of "wed": dt.weekday = dWed
|
|
||||||
of "thu": dt.weekday = dThu
|
|
||||||
of "fri": dt.weekday = dFri
|
|
||||||
of "sat": dt.weekday = dSat
|
|
||||||
else:
|
else:
|
||||||
raise newException(ValueError,
|
raise newException(ValueError,
|
||||||
|
"Couldn't parse day of month (d), got: " & value)
|
||||||
|
of "dd":
|
||||||
|
if value.len >= j+1:
|
||||||
|
dt.monthday = value[j..j+1].parseInt()
|
||||||
|
else:
|
||||||
|
raise newException(ValueError,
|
||||||
|
"Couldn't parse day of month (dd), got: " & value)
|
||||||
|
j += 2
|
||||||
|
of "ddd":
|
||||||
|
if value.len >= j+2:
|
||||||
|
case value[j..j+2].toLowerAscii()
|
||||||
|
of "sun": dt.weekday = dSun
|
||||||
|
of "mon": dt.weekday = dMon
|
||||||
|
of "tue": dt.weekday = dTue
|
||||||
|
of "wed": dt.weekday = dWed
|
||||||
|
of "thu": dt.weekday = dThu
|
||||||
|
of "fri": dt.weekday = dFri
|
||||||
|
of "sat": dt.weekday = dSat
|
||||||
|
else:
|
||||||
|
raise newException(ValueError,
|
||||||
"Couldn't parse day of week (ddd), got: " & value[j..j+2])
|
"Couldn't parse day of week (ddd), got: " & value[j..j+2])
|
||||||
|
else:
|
||||||
|
raise newException(ValueError,
|
||||||
|
"Couldn't parse day of week (ddd), got: " & value)
|
||||||
j += 3
|
j += 3
|
||||||
of "dddd":
|
of "dddd":
|
||||||
if value.len >= j+6 and value[j..j+5].cmpIgnoreCase("sunday") == 0:
|
if value.len >= j+6 and value[j..j+5].cmpIgnoreCase("sunday") == 0:
|
||||||
@@ -981,41 +993,69 @@ proc parseToken(dt: var DateTime; token, value: string; j: var int) =
|
|||||||
raise newException(ValueError,
|
raise newException(ValueError,
|
||||||
"Couldn't parse day of week (dddd), got: " & value)
|
"Couldn't parse day of week (dddd), got: " & value)
|
||||||
of "h", "H":
|
of "h", "H":
|
||||||
var pd = parseInt(value[j..j+1], sv)
|
if value.len >= j+1:
|
||||||
dt.hour = sv
|
var pd = parseInt(value[j..j+1], sv)
|
||||||
j += pd
|
dt.hour = sv
|
||||||
|
j += pd
|
||||||
|
else:
|
||||||
|
raise newException(ValueError,
|
||||||
|
"Couldn't parse hour (h), got: " & value)
|
||||||
of "hh", "HH":
|
of "hh", "HH":
|
||||||
dt.hour = value[j..j+1].parseInt()
|
if value.len >= j+1:
|
||||||
|
dt.hour = value[j..j+1].parseInt()
|
||||||
|
else:
|
||||||
|
raise newException(ValueError,
|
||||||
|
"Couldn't parse hour (hh), got: " & value)
|
||||||
j += 2
|
j += 2
|
||||||
of "m":
|
of "m":
|
||||||
var pd = parseInt(value[j..j+1], sv)
|
if value.len >= j+1:
|
||||||
dt.minute = sv
|
var pd = parseInt(value[j..j+1], sv)
|
||||||
j += pd
|
dt.minute = sv
|
||||||
|
j += pd
|
||||||
|
else:
|
||||||
|
raise newException(ValueError,
|
||||||
|
"Couldn't parse minute (m), got: " & value)
|
||||||
of "mm":
|
of "mm":
|
||||||
dt.minute = value[j..j+1].parseInt()
|
if value.len >= j+1:
|
||||||
|
dt.minute = value[j..j+1].parseInt()
|
||||||
|
else:
|
||||||
|
raise newException(ValueError,
|
||||||
|
"Couldn't parse minute (mm), got: " & value)
|
||||||
j += 2
|
j += 2
|
||||||
of "M":
|
of "M":
|
||||||
var pd = parseInt(value[j..j+1], sv)
|
if value.len >= j+1:
|
||||||
dt.month = sv.Month
|
var pd = parseInt(value[j..j+1], sv)
|
||||||
j += pd
|
dt.month = sv.Month
|
||||||
|
j += pd
|
||||||
|
else:
|
||||||
|
raise newException(ValueError,
|
||||||
|
"Couldn't parse month (M), got: " & value)
|
||||||
of "MM":
|
of "MM":
|
||||||
var month = value[j..j+1].parseInt()
|
if value.len >= j+1:
|
||||||
j += 2
|
var month = value[j..j+1].parseInt()
|
||||||
dt.month = month.Month
|
j += 2
|
||||||
|
dt.month = month.Month
|
||||||
|
else:
|
||||||
|
raise newException(ValueError,
|
||||||
|
"Couldn't parse month (MM), got: " & value)
|
||||||
of "MMM":
|
of "MMM":
|
||||||
case value[j..j+2].toLowerAscii():
|
if value.len >= j+2:
|
||||||
of "jan": dt.month = mJan
|
case value[j..j+2].toLowerAscii():
|
||||||
of "feb": dt.month = mFeb
|
of "jan": dt.month = mJan
|
||||||
of "mar": dt.month = mMar
|
of "feb": dt.month = mFeb
|
||||||
of "apr": dt.month = mApr
|
of "mar": dt.month = mMar
|
||||||
of "may": dt.month = mMay
|
of "apr": dt.month = mApr
|
||||||
of "jun": dt.month = mJun
|
of "may": dt.month = mMay
|
||||||
of "jul": dt.month = mJul
|
of "jun": dt.month = mJun
|
||||||
of "aug": dt.month = mAug
|
of "jul": dt.month = mJul
|
||||||
of "sep": dt.month = mSep
|
of "aug": dt.month = mAug
|
||||||
of "oct": dt.month = mOct
|
of "sep": dt.month = mSep
|
||||||
of "nov": dt.month = mNov
|
of "oct": dt.month = mOct
|
||||||
of "dec": dt.month = mDec
|
of "nov": dt.month = mNov
|
||||||
|
of "dec": dt.month = mDec
|
||||||
|
else:
|
||||||
|
raise newException(ValueError,
|
||||||
|
"Couldn't parse month (MMM), got: " & value)
|
||||||
else:
|
else:
|
||||||
raise newException(ValueError,
|
raise newException(ValueError,
|
||||||
"Couldn't parse month (MMM), got: " & value)
|
"Couldn't parse month (MMM), got: " & value)
|
||||||
@@ -1061,35 +1101,63 @@ proc parseToken(dt: var DateTime; token, value: string; j: var int) =
|
|||||||
raise newException(ValueError,
|
raise newException(ValueError,
|
||||||
"Couldn't parse month (MMMM), got: " & value)
|
"Couldn't parse month (MMMM), got: " & value)
|
||||||
of "s":
|
of "s":
|
||||||
var pd = parseInt(value[j..j+1], sv)
|
if value.len >= j+1:
|
||||||
dt.second = sv
|
var pd = parseInt(value[j..j+1], sv)
|
||||||
j += pd
|
dt.second = sv
|
||||||
|
j += pd
|
||||||
|
else:
|
||||||
|
raise newException(ValueError,
|
||||||
|
"Couldn't parse second (s), got: " & value)
|
||||||
of "ss":
|
of "ss":
|
||||||
dt.second = value[j..j+1].parseInt()
|
if value.len >= j+1:
|
||||||
|
dt.second = value[j..j+1].parseInt()
|
||||||
|
else:
|
||||||
|
raise newException(ValueError,
|
||||||
|
"Couldn't parse second (ss), got: " & value)
|
||||||
j += 2
|
j += 2
|
||||||
of "t":
|
of "t":
|
||||||
if value[j] == 'P' and dt.hour > 0 and dt.hour < 12:
|
if value[j] == 'P' and dt.hour > 0 and dt.hour < 12:
|
||||||
dt.hour += 12
|
dt.hour += 12
|
||||||
j += 1
|
j += 1
|
||||||
of "tt":
|
of "tt":
|
||||||
if value[j..j+1] == "PM" and dt.hour > 0 and dt.hour < 12:
|
if value.len >= j+1:
|
||||||
dt.hour += 12
|
if value[j..j+1] == "PM" and dt.hour > 0 and dt.hour < 12:
|
||||||
|
dt.hour += 12
|
||||||
|
else:
|
||||||
|
raise newException(ValueError,
|
||||||
|
"Couldn't parse hour (tt), got: " & value)
|
||||||
j += 2
|
j += 2
|
||||||
of "yy":
|
of "yy":
|
||||||
# Assumes current century
|
# Assumes current century
|
||||||
var year = value[j..j+1].parseInt()
|
if value.len >= j+1:
|
||||||
var thisCen = now().year div 100
|
var year = value[j..j+1].parseInt()
|
||||||
dt.year = thisCen*100 + year
|
var thisCen = now().year div 100
|
||||||
|
dt.year = thisCen*100 + year
|
||||||
|
else:
|
||||||
|
raise newException(ValueError,
|
||||||
|
"Couldn't parse year (yy), got: " & value)
|
||||||
j += 2
|
j += 2
|
||||||
of "yyyy":
|
of "yyyy":
|
||||||
dt.year = value[j..j+3].parseInt()
|
if value.len >= j+3:
|
||||||
|
dt.year = value[j..j+3].parseInt()
|
||||||
|
else:
|
||||||
|
raise newException(ValueError,
|
||||||
|
"Couldn't parse year (yyyy), got: " & value)
|
||||||
j += 4
|
j += 4
|
||||||
of "z":
|
of "z":
|
||||||
dt.isDst = false
|
dt.isDst = false
|
||||||
if value[j] == '+':
|
if value[j] == '+':
|
||||||
dt.utcOffset = 0 - parseInt($value[j+1]) * secondsInHour
|
if value.len >= j+1:
|
||||||
|
dt.utcOffset = 0 - parseInt($value[j+1]) * secondsInHour
|
||||||
|
else:
|
||||||
|
raise newException(ValueError,
|
||||||
|
"Couldn't parse timezone offset (z), got: " & value)
|
||||||
elif value[j] == '-':
|
elif value[j] == '-':
|
||||||
dt.utcOffset = parseInt($value[j+1]) * secondsInHour
|
if value.len >= j+1:
|
||||||
|
dt.utcOffset = parseInt($value[j+1]) * secondsInHour
|
||||||
|
else:
|
||||||
|
raise newException(ValueError,
|
||||||
|
"Couldn't parse timezone offset (z), got: " & value)
|
||||||
elif value[j] == 'Z':
|
elif value[j] == 'Z':
|
||||||
dt.utcOffset = 0
|
dt.utcOffset = 0
|
||||||
j += 1
|
j += 1
|
||||||
@@ -1101,9 +1169,17 @@ proc parseToken(dt: var DateTime; token, value: string; j: var int) =
|
|||||||
of "zz":
|
of "zz":
|
||||||
dt.isDst = false
|
dt.isDst = false
|
||||||
if value[j] == '+':
|
if value[j] == '+':
|
||||||
dt.utcOffset = 0 - value[j+1..j+2].parseInt() * secondsInHour
|
if value.len >= j+2:
|
||||||
|
dt.utcOffset = 0 - value[j+1..j+2].parseInt() * secondsInHour
|
||||||
|
else:
|
||||||
|
raise newException(ValueError,
|
||||||
|
"Couldn't parse timezone offset (zz), got: " & value)
|
||||||
elif value[j] == '-':
|
elif value[j] == '-':
|
||||||
dt.utcOffset = value[j+1..j+2].parseInt() * secondsInHour
|
if value.len >= j+2:
|
||||||
|
dt.utcOffset = value[j+1..j+2].parseInt() * secondsInHour
|
||||||
|
else:
|
||||||
|
raise newException(ValueError,
|
||||||
|
"Couldn't parse timezone offset (zz), got: " & value)
|
||||||
elif value[j] == 'Z':
|
elif value[j] == 'Z':
|
||||||
dt.utcOffset = 0
|
dt.utcOffset = 0
|
||||||
j += 1
|
j += 1
|
||||||
@@ -1124,10 +1200,14 @@ proc parseToken(dt: var DateTime; token, value: string; j: var int) =
|
|||||||
else:
|
else:
|
||||||
raise newException(ValueError,
|
raise newException(ValueError,
|
||||||
"Couldn't parse timezone offset (zzz), got: " & value[j])
|
"Couldn't parse timezone offset (zzz), got: " & value[j])
|
||||||
dt.utcOffset = factor * value[j+1..j+2].parseInt() * secondsInHour
|
if value.len >= j+5:
|
||||||
j += 4
|
dt.utcOffset = factor * value[j+1..j+2].parseInt() * secondsInHour
|
||||||
dt.utcOffset += factor * value[j..j+1].parseInt() * 60
|
j += 4
|
||||||
j += 2
|
dt.utcOffset += factor * value[j..j+1].parseInt() * 60
|
||||||
|
j += 2
|
||||||
|
else:
|
||||||
|
raise newException(ValueError,
|
||||||
|
"Couldn't parse timezone offset (zzz), got: " & value)
|
||||||
else:
|
else:
|
||||||
# Ignore the token and move forward in the value string by the same length
|
# Ignore the token and move forward in the value string by the same length
|
||||||
j += token.len
|
j += token.len
|
||||||
|
|||||||
@@ -131,6 +131,10 @@ template parseTest(s, f, sExpected: string, ydExpected: int) =
|
|||||||
echo parsed.yearday, " exp: ", ydExpected
|
echo parsed.yearday, " exp: ", ydExpected
|
||||||
check(parsed.yearday == ydExpected)
|
check(parsed.yearday == ydExpected)
|
||||||
|
|
||||||
|
template parseTestExcp(s, f: string) =
|
||||||
|
expect ValueError:
|
||||||
|
let parsed = s.parse(f)
|
||||||
|
|
||||||
template parseTestTimeOnly(s, f, sExpected: string) =
|
template parseTestTimeOnly(s, f, sExpected: string) =
|
||||||
check sExpected in $s.parse(f, utc())
|
check sExpected in $s.parse(f, utc())
|
||||||
|
|
||||||
@@ -281,6 +285,51 @@ suite "ttimes":
|
|||||||
test "parseTest":
|
test "parseTest":
|
||||||
runTimezoneTests()
|
runTimezoneTests()
|
||||||
|
|
||||||
|
test "incorrect inputs: empty string":
|
||||||
|
parseTestExcp("", "yyyy-MM-dd")
|
||||||
|
|
||||||
|
test "incorrect inputs: year":
|
||||||
|
parseTestExcp("20-02-19", "yyyy-MM-dd")
|
||||||
|
|
||||||
|
test "incorrect inputs: month number":
|
||||||
|
parseTestExcp("2018-2-19", "yyyy-MM-dd")
|
||||||
|
|
||||||
|
test "incorrect inputs: month name":
|
||||||
|
parseTestExcp("2018-Fe", "yyyy-MMM-dd")
|
||||||
|
|
||||||
|
test "incorrect inputs: day":
|
||||||
|
parseTestExcp("2018-02-1", "yyyy-MM-dd")
|
||||||
|
|
||||||
|
test "incorrect inputs: day of week":
|
||||||
|
parseTestExcp("2018-Feb-Mo", "yyyy-MMM-ddd")
|
||||||
|
|
||||||
|
test "incorrect inputs: hour":
|
||||||
|
parseTestExcp("2018-02-19 1:30", "yyyy-MM-dd hh:mm")
|
||||||
|
|
||||||
|
test "incorrect inputs: minute":
|
||||||
|
parseTestExcp("2018-02-19 16:3", "yyyy-MM-dd hh:mm")
|
||||||
|
|
||||||
|
test "incorrect inputs: second":
|
||||||
|
parseTestExcp("2018-02-19 16:30:0", "yyyy-MM-dd hh:mm:ss")
|
||||||
|
|
||||||
|
test "incorrect inputs: timezone (z)":
|
||||||
|
parseTestExcp("2018-02-19 16:30:00 ", "yyyy-MM-dd hh:mm:ss z")
|
||||||
|
|
||||||
|
test "incorrect inputs: timezone (zz) 1":
|
||||||
|
parseTestExcp("2018-02-19 16:30:00 ", "yyyy-MM-dd hh:mm:ss zz")
|
||||||
|
|
||||||
|
test "incorrect inputs: timezone (zz) 2":
|
||||||
|
parseTestExcp("2018-02-19 16:30:00 +1", "yyyy-MM-dd hh:mm:ss zz")
|
||||||
|
|
||||||
|
test "incorrect inputs: timezone (zzz) 1":
|
||||||
|
parseTestExcp("2018-02-19 16:30:00 ", "yyyy-MM-dd hh:mm:ss zzz")
|
||||||
|
|
||||||
|
test "incorrect inputs: timezone (zzz) 2":
|
||||||
|
parseTestExcp("2018-02-19 16:30:00 +01:", "yyyy-MM-dd hh:mm:ss zzz")
|
||||||
|
|
||||||
|
test "incorrect inputs: timezone (zzz) 3":
|
||||||
|
parseTestExcp("2018-02-19 16:30:00 +01:0", "yyyy-MM-dd hh:mm:ss zzz")
|
||||||
|
|
||||||
test "dynamic timezone":
|
test "dynamic timezone":
|
||||||
proc staticOffset(offset: int): Timezone =
|
proc staticOffset(offset: int): Timezone =
|
||||||
proc zoneInfoFromTz(adjTime: Time): ZonedTime =
|
proc zoneInfoFromTz(adjTime: Time): ZonedTime =
|
||||||
|
|||||||
Reference in New Issue
Block a user