mirror of
https://github.com/nim-lang/Nim.git
synced 2026-02-13 14:53:46 +00:00
Merge pull request #921 from gradha/pr_improves_times_format
Improves times.format parsing, fixes #740
This commit is contained in:
@@ -557,6 +557,119 @@ proc `$`*(m: TMonth): string =
|
||||
"November", "December"]
|
||||
return lookup[m]
|
||||
|
||||
proc format_token(info: TTimeInfo, token: string, buf: var string) =
|
||||
## Helper of the format proc to parse individual tokens.
|
||||
##
|
||||
## Pass the found token in the user input string, and the buffer where the
|
||||
## final string is being built. This has to be a var value because certain
|
||||
## formatting tokens require modifying the previous characters.
|
||||
case token
|
||||
of "d":
|
||||
buf.add($info.monthday)
|
||||
of "dd":
|
||||
if info.monthday < 10:
|
||||
buf.add("0")
|
||||
buf.add($info.monthday)
|
||||
of "ddd":
|
||||
buf.add(($info.weekday)[0 .. 2])
|
||||
of "dddd":
|
||||
buf.add($info.weekday)
|
||||
of "h":
|
||||
buf.add($(if info.hour > 12: info.hour - 12 else: info.hour))
|
||||
of "hh":
|
||||
let amerHour = if info.hour > 12: info.hour - 12 else: info.hour
|
||||
if amerHour < 10:
|
||||
buf.add('0')
|
||||
buf.add($amerHour)
|
||||
of "H":
|
||||
buf.add($info.hour)
|
||||
of "HH":
|
||||
if info.hour < 10:
|
||||
buf.add('0')
|
||||
buf.add($info.hour)
|
||||
of "m":
|
||||
buf.add($info.minute)
|
||||
of "mm":
|
||||
if info.minute < 10:
|
||||
buf.add('0')
|
||||
buf.add($info.minute)
|
||||
of "M":
|
||||
buf.add($(int(info.month)+1))
|
||||
of "MM":
|
||||
if info.month < mOct:
|
||||
buf.add('0')
|
||||
buf.add($(int(info.month)+1))
|
||||
of "MMM":
|
||||
buf.add(($info.month)[0..2])
|
||||
of "MMMM":
|
||||
buf.add($info.month)
|
||||
of "s":
|
||||
buf.add($info.second)
|
||||
of "ss":
|
||||
if info.second < 10:
|
||||
buf.add('0')
|
||||
buf.add($info.second)
|
||||
of "t":
|
||||
if info.hour >= 12:
|
||||
buf.add('P')
|
||||
else: buf.add('A')
|
||||
of "tt":
|
||||
if info.hour >= 12:
|
||||
buf.add("PM")
|
||||
else: buf.add("AM")
|
||||
of "y":
|
||||
var fr = ($info.year).len()-1
|
||||
if fr < 0: fr = 0
|
||||
buf.add(($info.year)[fr .. ($info.year).len()-1])
|
||||
of "yy":
|
||||
var fr = ($info.year).len()-2
|
||||
if fr < 0: fr = 0
|
||||
var fyear = ($info.year)[fr .. ($info.year).len()-1]
|
||||
if fyear.len != 2: fyear = repeatChar(2-fyear.len(), '0') & fyear
|
||||
buf.add(fyear)
|
||||
of "yyy":
|
||||
var fr = ($info.year).len()-3
|
||||
if fr < 0: fr = 0
|
||||
var fyear = ($info.year)[fr .. ($info.year).len()-1]
|
||||
if fyear.len != 3: fyear = repeatChar(3-fyear.len(), '0') & fyear
|
||||
buf.add(fyear)
|
||||
of "yyyy":
|
||||
var fr = ($info.year).len()-4
|
||||
if fr < 0: fr = 0
|
||||
var fyear = ($info.year)[fr .. ($info.year).len()-1]
|
||||
if fyear.len != 4: fyear = repeatChar(4-fyear.len(), '0') & fyear
|
||||
buf.add(fyear)
|
||||
of "yyyyy":
|
||||
var fr = ($info.year).len()-5
|
||||
if fr < 0: fr = 0
|
||||
var fyear = ($info.year)[fr .. ($info.year).len()-1]
|
||||
if fyear.len != 5: fyear = repeatChar(5-fyear.len(), '0') & fyear
|
||||
buf.add(fyear)
|
||||
of "z":
|
||||
let hrs = (info.timezone div 60) div 60
|
||||
buf.add($hrs)
|
||||
of "zz":
|
||||
let hrs = (info.timezone div 60) div 60
|
||||
|
||||
buf.add($hrs)
|
||||
if hrs.abs < 10:
|
||||
var atIndex = buf.len-(($hrs).len-(if hrs < 0: 1 else: 0))
|
||||
buf.insert("0", atIndex)
|
||||
of "zzz":
|
||||
let hrs = (info.timezone div 60) div 60
|
||||
|
||||
buf.add($hrs & ":00")
|
||||
if hrs.abs < 10:
|
||||
var atIndex = buf.len-(($hrs & ":00").len-(if hrs < 0: 1 else: 0))
|
||||
buf.insert("0", atIndex)
|
||||
of "ZZZ":
|
||||
buf.add(info.tzname)
|
||||
of "":
|
||||
discard
|
||||
else:
|
||||
raise newException(EInvalidValue, "Invalid format string: " & token)
|
||||
|
||||
|
||||
proc format*(info: TTimeInfo, f: string): string =
|
||||
## This function formats `info` as specified by `f`. The following format
|
||||
## specifiers are available:
|
||||
@@ -591,8 +704,11 @@ proc format*(info: TTimeInfo, f: string): string =
|
||||
## ZZZ Displays the name of the timezone. ``GMT -> GMT``, ``EST -> EST``
|
||||
## ========== ================================================================================= ================================================
|
||||
##
|
||||
## Other strings can be inserted by putting them in ``''``. For example ``hh'->'mm`` will give ``01->56``.
|
||||
## The following characters can be inserted without quoting them: ``:`` ``-`` ``(`` ``)`` ``/`` ``[`` ``]`` ``,``
|
||||
## Other strings can be inserted by putting them in ``''``. For example
|
||||
## ``hh'->'mm`` will give ``01->56``. The following characters can be
|
||||
## inserted without quoting them: ``:`` ``-`` ``(`` ``)`` ``/`` ``[`` ``]``
|
||||
## ``,``. However you don't need to necessarily separate format specifiers, a
|
||||
## unambiguous format string like ``yyyyMMddhhmmss`` is valid too.
|
||||
|
||||
result = ""
|
||||
var i = 0
|
||||
@@ -600,112 +716,8 @@ proc format*(info: TTimeInfo, f: string): string =
|
||||
while true:
|
||||
case f[i]
|
||||
of ' ', '-', '/', ':', '\'', '\0', '(', ')', '[', ']', ',':
|
||||
case currentF
|
||||
of "d":
|
||||
result.add($info.monthday)
|
||||
of "dd":
|
||||
if info.monthday < 10:
|
||||
result.add("0")
|
||||
result.add($info.monthday)
|
||||
of "ddd":
|
||||
result.add(($info.weekday)[0 .. 2])
|
||||
of "dddd":
|
||||
result.add($info.weekday)
|
||||
of "h":
|
||||
result.add($(if info.hour > 12: info.hour - 12 else: info.hour))
|
||||
of "hh":
|
||||
let amerHour = if info.hour > 12: info.hour - 12 else: info.hour
|
||||
if amerHour < 10:
|
||||
result.add('0')
|
||||
result.add($amerHour)
|
||||
of "H":
|
||||
result.add($info.hour)
|
||||
of "HH":
|
||||
if info.hour < 10:
|
||||
result.add('0')
|
||||
result.add($info.hour)
|
||||
of "m":
|
||||
result.add($info.minute)
|
||||
of "mm":
|
||||
if info.minute < 10:
|
||||
result.add('0')
|
||||
result.add($info.minute)
|
||||
of "M":
|
||||
result.add($(int(info.month)+1))
|
||||
of "MM":
|
||||
if info.month < mOct:
|
||||
result.add('0')
|
||||
result.add($(int(info.month)+1))
|
||||
of "MMM":
|
||||
result.add(($info.month)[0..2])
|
||||
of "MMMM":
|
||||
result.add($info.month)
|
||||
of "s":
|
||||
result.add($info.second)
|
||||
of "ss":
|
||||
if info.second < 10:
|
||||
result.add('0')
|
||||
result.add($info.second)
|
||||
of "t":
|
||||
if info.hour >= 12:
|
||||
result.add('P')
|
||||
else: result.add('A')
|
||||
of "tt":
|
||||
if info.hour >= 12:
|
||||
result.add("PM")
|
||||
else: result.add("AM")
|
||||
of "y":
|
||||
var fr = ($info.year).len()-1
|
||||
if fr < 0: fr = 0
|
||||
result.add(($info.year)[fr .. ($info.year).len()-1])
|
||||
of "yy":
|
||||
var fr = ($info.year).len()-2
|
||||
if fr < 0: fr = 0
|
||||
var fyear = ($info.year)[fr .. ($info.year).len()-1]
|
||||
if fyear.len != 2: fyear = repeatChar(2-fyear.len(), '0') & fyear
|
||||
result.add(fyear)
|
||||
of "yyy":
|
||||
var fr = ($info.year).len()-3
|
||||
if fr < 0: fr = 0
|
||||
var fyear = ($info.year)[fr .. ($info.year).len()-1]
|
||||
if fyear.len != 3: fyear = repeatChar(3-fyear.len(), '0') & fyear
|
||||
result.add(fyear)
|
||||
of "yyyy":
|
||||
var fr = ($info.year).len()-4
|
||||
if fr < 0: fr = 0
|
||||
var fyear = ($info.year)[fr .. ($info.year).len()-1]
|
||||
if fyear.len != 4: fyear = repeatChar(4-fyear.len(), '0') & fyear
|
||||
result.add(fyear)
|
||||
of "yyyyy":
|
||||
var fr = ($info.year).len()-5
|
||||
if fr < 0: fr = 0
|
||||
var fyear = ($info.year)[fr .. ($info.year).len()-1]
|
||||
if fyear.len != 5: fyear = repeatChar(5-fyear.len(), '0') & fyear
|
||||
result.add(fyear)
|
||||
of "z":
|
||||
let hrs = (info.timezone div 60) div 60
|
||||
result.add($hrs)
|
||||
of "zz":
|
||||
let hrs = (info.timezone div 60) div 60
|
||||
|
||||
result.add($hrs)
|
||||
if hrs.abs < 10:
|
||||
var atIndex = result.len-(($hrs).len-(if hrs < 0: 1 else: 0))
|
||||
result.insert("0", atIndex)
|
||||
of "zzz":
|
||||
let hrs = (info.timezone div 60) div 60
|
||||
|
||||
result.add($hrs & ":00")
|
||||
if hrs.abs < 10:
|
||||
var atIndex = result.len-(($hrs & ":00").len-(if hrs < 0: 1 else: 0))
|
||||
result.insert("0", atIndex)
|
||||
of "ZZZ":
|
||||
result.add(info.tzname)
|
||||
of "":
|
||||
discard
|
||||
else:
|
||||
raise newException(EInvalidValue, "Invalid format string: " & currentF)
|
||||
|
||||
format_token(info, currentF, result)
|
||||
|
||||
currentF = ""
|
||||
if f[i] == '\0': break
|
||||
|
||||
@@ -716,7 +728,15 @@ proc format*(info: TTimeInfo, f: string): string =
|
||||
inc(i)
|
||||
else: result.add(f[i])
|
||||
|
||||
else: currentF.add(f[i])
|
||||
else:
|
||||
# Check if the letter being added matches previous accumulated buffer.
|
||||
if currentF.len < 1 or currentF[high(currentF)] == f[i]:
|
||||
currentF.add(f[i])
|
||||
else:
|
||||
format_token(info, currentF, result)
|
||||
dec(i) # Move position back to re-process the character separately.
|
||||
currentF = ""
|
||||
|
||||
inc(i)
|
||||
|
||||
{.pop.}
|
||||
@@ -727,11 +747,15 @@ when isMainModule:
|
||||
|
||||
var t = getGMTime(fromSeconds(2147483647))
|
||||
echo t.format("ddd dd MMM hh:mm:ss ZZZ yyyy")
|
||||
echo t.format("ddd ddMMMhhmmssZZZyyyy")
|
||||
assert t.format("ddd dd MMM hh:mm:ss ZZZ yyyy") == "Tue 19 Jan 03:14:07 UTC 2038"
|
||||
assert t.format("ddd ddMMMhh:mm:ssZZZyyyy") == "Tue 19Jan03:14:07UTC2038"
|
||||
|
||||
assert t.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") ==
|
||||
"19 19 Tue Tuesday 3 03 3 03 14 14 1 01 Jan January 7 07 A AM 8 38 038 2038 02038 0 00 00:00 UTC"
|
||||
|
||||
assert t.format("yyyyMMddhhmmss") == "20380119031407"
|
||||
|
||||
var t2 = getGMTime(fromSeconds(160070789)) # Mon 27 Jan 16:06:29 GMT 1975
|
||||
assert t2.format("d dd ddd dddd h hh H HH m mm M MM MMM MMMM s" &
|
||||
|
||||
Reference in New Issue
Block a user