Date/time parsing with changes suggested by Araq
This commit is contained in:
parent
5424ab3d7e
commit
3643068527
1 changed files with 283 additions and 334 deletions
|
|
@ -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"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue