|
|
|
@ -9,6 +9,8 @@ type
|
|
|
|
|
Timeline* = tuple[name: string, marks: seq[Mark]]
|
|
|
|
|
## Representation of a timeline: a name and sequence of Marks.
|
|
|
|
|
|
|
|
|
|
OffsetFrom = enum Year, Month, Day, None
|
|
|
|
|
|
|
|
|
|
const STOP_MSG* = "STOP"
|
|
|
|
|
|
|
|
|
|
let NO_MARK*: Mark = (
|
|
|
|
@ -20,11 +22,18 @@ const ISO_TIME_FORMAT* = "yyyy-MM-dd'T'HH:mm:ss"
|
|
|
|
|
## The canonical time format used by PTK.
|
|
|
|
|
|
|
|
|
|
const TIME_FORMATS* = @[
|
|
|
|
|
"yyyy-MM-dd'T'HH:mm:ss", "yyyy-MM-dd HH:mm:ss",
|
|
|
|
|
"yyyy-MM-dd'T'HH:mm", "yyyy-MM-dd HH:mm",
|
|
|
|
|
"MM-dd'T'HH:mm:ss", "MM-dd HH:mm:ss",
|
|
|
|
|
"MM-dd'T'HH:mm", "MM-dd HH:mm",
|
|
|
|
|
"HH:mm:ss", "H:mm:ss", "H:mm", "HH:mm" ]
|
|
|
|
|
(fmtStr: "yyyy-MM-dd'T'HH:mm:ss", offsetFrom: OffsetFrom.None),
|
|
|
|
|
(fmtStr: "yyyy-MM-dd HH:mm:ss", offsetFrom: OffsetFrom.None),
|
|
|
|
|
(fmtStr: "yyyy-MM-dd'T'HH:mm", offsetFrom: OffsetFrom.None),
|
|
|
|
|
(fmtStr: "yyyy-MM-dd HH:mm", offsetFrom: OffsetFrom.None),
|
|
|
|
|
(fmtStr: "MM-dd'T'HH:mm:ss", offsetFrom: OffsetFrom.Year),
|
|
|
|
|
(fmtStr: "MM-dd HH:mm:ss", offsetFrom: OffsetFrom.Year),
|
|
|
|
|
(fmtStr: "MM-dd'T'HH:mm", offsetFrom: OffsetFrom.Year),
|
|
|
|
|
(fmtStr: "MM-dd HH:mm", offsetFrom: OffsetFrom.Year),
|
|
|
|
|
(fmtStr: "HH:mm:ss", offsetFrom: OffsetFrom.Day),
|
|
|
|
|
(fmtStr: "H:mm:ss", offsetFrom: OffsetFrom.Day),
|
|
|
|
|
(fmtStr: "H:mm", offsetFrom: OffsetFrom.Day),
|
|
|
|
|
(fmtStr: "HH:mm", offsetFrom: OffsetFrom.Day) ]
|
|
|
|
|
## Other time formats that PTK will accept as input.
|
|
|
|
|
|
|
|
|
|
proc getOrFail*(n: JsonNode, key: string, objName: string = ""): JsonNode =
|
|
|
|
@ -40,7 +49,23 @@ proc getIfExists*(n: JsonNode, key: string): JsonNode =
|
|
|
|
|
proc parseTime*(timeStr: string): DateTime =
|
|
|
|
|
## Helper to parse time strings trying multiple known formats.
|
|
|
|
|
for fmt in TIME_FORMATS:
|
|
|
|
|
try: return parse(timeStr, fmt)
|
|
|
|
|
try:
|
|
|
|
|
let now = now()
|
|
|
|
|
let parsed = parse(timeStr, fmt.fmtStr)
|
|
|
|
|
case fmt.offsetFrom:
|
|
|
|
|
of OffsetFrom.None:
|
|
|
|
|
return parsed
|
|
|
|
|
of OffsetFrom.Year:
|
|
|
|
|
return initDateTime(parsed.monthday, parsed.month, now.year,
|
|
|
|
|
parsed.hour, parsed.minute, parsed.second, parsed.nanosecond,
|
|
|
|
|
now.timezone)
|
|
|
|
|
of OffsetFrom.Month:
|
|
|
|
|
return initDateTime(parsed.monthday, now.month, now.year,
|
|
|
|
|
parsed.hour, parsed.minute, parsed.second, parsed.nanosecond,
|
|
|
|
|
now.timezone)
|
|
|
|
|
of OffsetFrom.Day:
|
|
|
|
|
return initDateTime(now.monthday, now.month, now.year, parsed.hour,
|
|
|
|
|
parsed.minute, parsed.second, parsed.nanosecond, now.timezone)
|
|
|
|
|
except: discard nil
|
|
|
|
|
|
|
|
|
|
raise newException(Exception, "unable to interpret as a date: " & timeStr)
|
|
|
|
@ -112,5 +137,3 @@ proc getLastIndex*(marks: seq[Mark]): int =
|
|
|
|
|
while idx >= 0 and marks[idx].summary == STOP_MSG: idx -= 1
|
|
|
|
|
if idx < 0: result = -1
|
|
|
|
|
else: result = idx
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|