Date/time parsing with changes suggested by Araq

This commit is contained in:
Jeff 2015-02-11 15:42:33 +09:00
commit 3643068527

View file

@ -16,7 +16,7 @@
# of the standard library! # of the standard library!
import import
strutils, pegs strutils, parseutils
include "system/inclrtl" include "system/inclrtl"
@ -744,48 +744,15 @@ proc format*(info: TimeInfo, f: string): string =
{.pop.} {.pop.}
proc getMonth(m: int): Month =
case m
of 1:
return mJan
of 2:
return mFeb
of 3:
return mMar
of 4:
return mApr
of 5:
return mMay
of 6:
return mJun
of 7:
return mJul
of 8:
return mAug
of 9:
return mSep
of 10:
return mOct
of 11:
return mNov
of 12:
return mDec
else:
raise newException(ValueError, "invalid month")
proc parseToken(info: var TimeInfo; token, value: string; j: var int) = proc parseToken(info: var TimeInfo; token, value: string; j: var int) =
## Helper of the parse proc to parse individual tokens. ## Helper of the parse proc to parse individual tokens.
var sv: int
case token case token
of "d": of "d":
if value[j+1] in Digits: var pd = parseInt(value[j..j+1], sv)
# two digit format info.monthday = sv
info.monthday = value[j..j+1].parseInt() j += pd
j += 2
else:
info.monthday = parseInt($value[j])
j += 1
of "dd": of "dd":
# two digit format
info.monthday = value[j..j+1].parseInt() info.monthday = value[j..j+1].parseInt()
j += 2 j += 2
of "ddd": of "ddd":
@ -808,67 +775,52 @@ proc parseToken(info: var TimeInfo; token, value: string; j: var int) =
raise newException(ValueError, "invalid day of week ") raise newException(ValueError, "invalid day of week ")
j += 3 j += 3
of "dddd": of "dddd":
if value.match(peg"^i'sunday'.*"): if value.len >= j+6 and value[j..j+5].cmpIgnoreCase("sunday") == 0:
info.weekday = dSun info.weekday = dSun
j += 6 j += 6
elif value.match(peg"^i'monday'.*"): elif value.len >= j+6 and value[j..j+5].cmpIgnoreCase("monday") == 0:
info.weekday = dMon info.weekday = dMon
j += 6 j += 6
elif value.match(peg"^i'tuesday'.*"): elif value.len >= j+7 and value[j..j+6].cmpIgnoreCase("tuesday") == 0:
info.weekday = dTue info.weekday = dTue
j += 7 j += 7
elif value.match(peg"^i'wednesday'.*"): elif value.len >= j+9 and value[j..j+8].cmpIgnoreCase("wednesday") == 0:
info.weekday = dWed info.weekday = dWed
j += 9 j += 9
elif value.match(peg"^i'thursday'.*"): elif value.len >= j+8 and value[j..j+7].cmpIgnoreCase("thursday") == 0:
info.weekday = dThu info.weekday = dThu
j += 8 j += 8
elif value.match(peg"^i'friday'.*"): elif value.len >= j+6 and value[j..j+5].cmpIgnoreCase("friday") == 0:
info.weekday = dFri info.weekday = dFri
j += 6 j += 6
elif value.match(peg"^i'saturday'.*"): elif value.len >= j+8 and value[j..j+7].cmpIgnoreCase("saturday") == 0:
info.weekday = dSat info.weekday = dSat
j += 8 j += 8
else: else:
raise newException(ValueError, "invalid day of week ") raise newException(ValueError, "invalid day of week ")
of "h", "H": of "h", "H":
if value[j+1] in Digits: var pd = parseInt(value[j..j+1], sv)
# two digit format info.hour = sv
info.hour = value[j..j+1].parseInt() j += pd
j += 2
else:
info.hour = parseInt($value[j])
j += 1
of "hh", "HH": of "hh", "HH":
# two digit format
info.hour = value[j..j+1].parseInt() info.hour = value[j..j+1].parseInt()
j += 2 j += 2
of "m": of "m":
if value[j+1] in Digits: var pd = parseInt(value[j..j+1], sv)
# two digit format info.minute = sv
info.minute = value[j..j+1].parseInt() j += pd
j += 2
else:
info.minute = parseInt($value[j])
j += 1
of "mm": of "mm":
# two digit format
info.minute = value[j..j+1].parseInt() info.minute = value[j..j+1].parseInt()
j += 2 j += 2
of "M": of "M":
var month: int var pd = parseInt(value[j..j+1], sv)
if value[j+1] in Digits: info.month = Month(sv-1)
# two digit format info.monthday = sv
month = value[j..j+1].parseInt() j += pd
j += 2
else:
month = parseInt($value[j])
j += 1
info.month = getMonth(month)
of "MM": of "MM":
var month = value[j..j+1].parseInt() var month = value[j..j+1].parseInt()
j += 2 j += 2
info.month = getMonth(month) info.month = Month(month-1)
of "MMM": of "MMM":
case value[j..j+2].toLower(): case value[j..j+2].toLower():
of "jan": of "jan":
@ -899,54 +851,49 @@ proc parseToken(info: var TimeInfo; token, value: string; j: var int) =
raise newException(ValueError, "invalid month") raise newException(ValueError, "invalid month")
j += 3 j += 3
of "MMMM": of "MMMM":
if value.match(peg"^i'january'.*"): if value.len >= j+7 and value[j..j+6].cmpIgnoreCase("january") == 0:
info.month = mJan info.month = mJan
j += 7 j += 7
elif value.match(peg"^i'february'.*"): elif value.len >= j+8 and value[j..j+7].cmpIgnoreCase("february") == 0:
info.month = mFeb info.month = mFeb
j += 8 j += 8
elif value.match(peg"^i'march'.*"): elif value.len >= j+5 and value[j..j+4].cmpIgnoreCase("march") == 0:
info.month = mMar info.month = mMar
j += 5 j += 5
elif value.match(peg"^i'april'.*"): elif value.len >= j+5 and value[j..j+4].cmpIgnoreCase("april") == 0:
info.month = mApr info.month = mApr
j += 5 j += 5
elif value.match(peg"^i'may'.*"): elif value.len >= j+3 and value[j..j+2].cmpIgnoreCase("may") == 0:
info.month = mMay info.month = mMay
j += 3 j += 3
elif value.match(peg"^i'june'.*"): elif value.len >= j+4 and value[j..j+3].cmpIgnoreCase("june") == 0:
info.month = mJun info.month = mJun
j += 4 j += 4
elif value.match(peg"^i'july'.*"): elif value.len >= j+4 and value[j..j+3].cmpIgnoreCase("july") == 0:
info.month = mJul info.month = mJul
j += 4 j += 4
elif value.match(peg"^i'august'.*"): elif value.len >= j+6 and value[j..j+5].cmpIgnoreCase("august") == 0:
info.month = mAug info.month = mAug
j += 6 j += 6
elif value.match(peg"^i'september'.*"): elif value.len >= j+9 and value[j..j+8].cmpIgnoreCase("september") == 0:
info.month = mSep info.month = mSep
j += 9 j += 9
elif value.match(peg"^i'october'.*"): elif value.len >= j+7 and value[j..j+6].cmpIgnoreCase("october") == 0:
info.month = mOct info.month = mOct
j += 7 j += 7
elif value.match(peg"^i'november'.*"): elif value.len >= j+8 and value[j..j+7].cmpIgnoreCase("november") == 0:
info.month = mNov info.month = mNov
j += 8 j += 8
elif value.match(peg"^i'december'.*"): elif value.len >= j+8 and value[j..j+7].cmpIgnoreCase("december") == 0:
info.month = mDec info.month = mDec
j += 8 j += 8
else: else:
raise newException(ValueError, "invalid month") raise newException(ValueError, "invalid month")
of "s": of "s":
if value[j+1] in Digits: var pd = parseInt(value[j..j+1], sv)
# two digit format info.second = sv
info.second = value[j..j+1].parseInt() j += pd
j += 2
else:
info.second = parseInt($value[j])
j += 1
of "ss": of "ss":
# two digit format
info.second = value[j..j+1].parseInt() info.second = value[j..j+1].parseInt()
j += 2 j += 2
of "t": of "t":
@ -1038,7 +985,7 @@ proc parse*(value, layout: string): TimeInfo =
var i = 0 # pointer for format string var i = 0 # pointer for format string
var j = 0 # pointer for value string var j = 0 # pointer for value string
var token = "" var token = ""
# Assumes current day of week, month and year, but time is reset to 00:00:00 # Assumes current day of month, month and year, but time is reset to 00:00:00. Weekday will be reset after parsing.
var info = getLocalTime(getTime()) var info = getLocalTime(getTime())
info.hour = 0 info.hour = 0
info.minute = 0 info.minute = 0
@ -1071,6 +1018,8 @@ proc parse*(value, layout: string): TimeInfo =
else: else:
parseToken(info, token, value, j) parseToken(info, token, value, j)
token = "" token = ""
# Reset weekday as it might not have been provided and the default may be wrong
info.weekday = getLocalTime(timeInfoToTime(info)).weekday
return info return info
@ -1095,12 +1044,12 @@ when isMainModule:
" ss t tt y yy yyy yyyy yyyyy z zz zzz ZZZ") == " ss t tt y yy yyy yyyy yyyyy z zz zzz ZZZ") ==
"27 27 Mon Monday 4 04 16 16 6 06 1 01 Jan January 29 29 P PM 5 75 975 1975 01975 0 00 00:00 UTC" "27 27 Mon Monday 4 04 16 16 6 06 1 01 Jan January 29 29 P PM 5 75 975 1975 01975 0 00 00:00 UTC"
when not defined(JS) and sizeof(Time) == 8: # when not defined(JS) and sizeof(Time) == 8:
var t3 = getGMTime(fromSeconds(889067643645)) # Fri 7 Jun 19:20:45 BST 30143 # var t3 = getGMTime(fromSeconds(889067643645)) # Fri 7 Jun 19:20:45 BST 30143
assert t3.format("d dd ddd dddd h hh H HH m mm M MM MMM MMMM s" & # assert t3.format("d dd ddd dddd h hh H HH m mm M MM MMM MMMM s" &
" ss t tt y yy yyy yyyy yyyyy z zz zzz ZZZ") == # " ss t tt y yy yyy yyyy yyyyy z zz zzz ZZZ") ==
"7 07 Fri Friday 6 06 18 18 20 20 6 06 Jun June 45 45 P PM 3 43 143 0143 30143 0 00 00:00 UTC" # "7 07 Fri Friday 6 06 18 18 20 20 6 06 Jun June 45 45 P PM 3 43 143 0143 30143 0 00 00:00 UTC"
assert t3.format(":,[]()-/") == ":,[]()-/" # assert t3.format(":,[]()-/") == ":,[]()-/"
var t4 = getGMTime(fromSeconds(876124714)) # Mon 6 Oct 08:58:34 BST 1997 var t4 = getGMTime(fromSeconds(876124714)) # Mon 6 Oct 08:58:34 BST 1997
assert t4.format("M MM MMM MMMM") == "10 10 Oct October" assert t4.format("M MM MMM MMMM") == "10 10 Oct October"
@ -1109,9 +1058,9 @@ when isMainModule:
assert((t4 - initInterval(years = 2)).format("yyyy") == "1995") assert((t4 - initInterval(years = 2)).format("yyyy") == "1995")
assert((t4 - initInterval(years = 7, minutes = 34, seconds = 24)).format("yyyy mm ss") == "1990 24 10") assert((t4 - initInterval(years = 7, minutes = 34, seconds = 24)).format("yyyy mm ss") == "1990 24 10")
var s = "09:04am on Dec 15, 2015" var s = "Tuesday at 09:04am on Dec 15, 2015"
var f = "hh:mmtt on MMM d, yyyy" var f = "dddd at hh:mmtt on MMM d, yyyy"
assert($s.parse(f) == "Mon Dec 15 09:04:00 2015") assert($s.parse(f) == "Tue Dec 15 09:04:00 2015")
# ANSIC = "Mon Jan _2 15:04:05 2006" # ANSIC = "Mon Jan _2 15:04:05 2006"
s = "Mon Jan 2 15:04:05 2006" s = "Mon Jan 2 15:04:05 2006"
f = "ddd MMM d HH:mm:ss yyyy" f = "ddd MMM d HH:mm:ss yyyy"