ref: f7228d204a9cbe40f7b6286ba8987ef65691bfbd
dir: /lib/date/parse.myr/
use std use "types.use" use "names.use" pkg date = /* date i/o */ const parsefmt : (f : byte[:], s: byte[:] -> std.option(instant)) const parsefmtz : (f : byte[:], s: byte[:], tz : byte[:] -> std.option(instant)) ;; const UnixJulianDiff = 719468 const parsefmt = {f, s; -> parsefmtz(f, s, "")} const parsefmtz = {f, s, tz var d var err d = [.year = 0] err = false s = filldate(&d, f, s, tz, &err) if err || s.len > 0 -> `std.None ;; -> `std.Some d } generic intval = {dst : @a::(numeric,integral)#, s : byte[:], min : @a::(numeric,integral), max : @a::(numeric,integral), err : bool# -> byte[:] var i var c var num num = s for i = 0; i < min; i++ (c, s) = std.striter(s) if !std.isdigit(c) err# = true -> s ;; ;; for i = min ; i < max; i++ (c, s) = std.striter(s) if !std.isdigit(c) break ;; ;; num = num[:i] match std.intparse(num) | `std.Some v: dst# = v -> s | `std.None: err# = true -> s ;; } const filldate = {d, f, s, tz, err -> byte[:] var fc, sc while f.len != 0 (fc, f) = std.striter(f) if fc == '%' (fc, f) = std.striter(f) match fc /* named things */ | 'a': s = indexof(&d.day, s, _names.abbrevday, err) | 'A': s = indexof(&d.day, s, _names.fullday, err) | 'b': s = indexof(&d.mon, s, _names.abbrevmon, err) | 'B': s = indexof(&d.mon, s, _names.fullmon, err) | 'c': s = filldate(d, "%Y-%m-%d", s, tz, err) | 'C': s = intval(&d.year, s, 2, 2, err) d.year += 1900 | 'd': s = intval(&d.day, s, 2, 2, err) | 'D': s = filldate(d, "%m/%d/%y", s, tz, err) | 'e': s = intval(&d.day, s, 1, 2, err) | 'F': s = filldate(d, "%y-%m-%d", s, tz, err) /* | 'G': o += std.bfmt(buf[o:], ...? | 'g': */ | 'h': s = indexof(&d.day, s, _names.abbrevmon, err) | 'H': s = intval(&d.h, s, 2, 2, err) | 'I': s = intval(&d.h, s, 2, 2, err) | 'j': std.fatal("unsupported '%j'\n") | 'k': s = intval(&d.h, s, 1, 2, err) | 'l': s = intval(&d.h, s, 1, 2, err) | 'm': s = intval(&d.mon, s, 1, 2, err) | 'M': s = intval(&d.m, s, 1, 2, err) | 'n': s = matchstr(s, "\n", err) | 'O': std.fatal("unsupported %O\n") | 'p': s = matchampm(d, s, err) | 'P': s = matchampm(d, s, err) | 'r': s = filldate(d, "%H:%M:%S %P", s, tz, err) | 'R': s = filldate(d, "%H:%M %P", s, tz, err) | 's': s = intval(&d.actual, s, 1, 64, err) | 'S': s = intval(&d.s, s, 1, 2, err) | 't': s = eatspace(s) | 'u': s = intval(&d.wday, s, 1, 1, err) | 'U': std.fatal("unsupported '%U'\n") /* | 'x': o += bftime(buf[o:], Datefmt, d) | 'X': o += bftime(buf[o:], Timefmt, d) */ | 'y': s = intval(&d.year, s, 1, 2, err) d.year += 1900 | 'Y': s = intval(&d.year, s, 1, 4, err) | 'z': s = timezone(&d.tzoff, s, err) /* | 'Z': o += std.bfmt(buf[o:], "%s", d.tzname) */ | '%': s = matchstr(s, "%", err) | _: std.fatal("unknown format character %c\n", fc) ;; else (sc, s) = std.striter(s) if std.isspace(sc) s = eatspace(s) elif (sc != fc) err# = true -> s ;; ;; if err# -> s ;; ;; d.actual = time(d) -> s } const eatspace = {s var c while std.isspace(std.decode(s)) (c, s) = std.striter(s) ;; -> s } const indexof = {dst, s, set, err var i for i = 0; i < set.len; i++ if s.len >= set[i].len && std.streq(s, set[i]) dst# = i -> s ;; ;; err# = true dst# = 0 -> s } const timezone = {dst, s, err var isneg var tzoff if s.len < 1 err# = true -> "" ;; if std.sleq(s[:1], "-") isneg = true elif std.sleq(s[:1], "+") isneg = false else err# = true -> "" ;; s = intval(&tzoff, s[1:], 2, 4, err) dst# = (tzoff / 100) * 3600 * 1_000_000 + (tzoff % 100) * 60 * 1_000_000 -> s } const matchstr = {s, str, err if s.len <= str.len || !std.sleq(s[:str.len], str) err# = true -> "" ;; -> s[str.len:] } const matchampm = {d, s, err if s.len < 2 err# = true -> s ;; if std.sleq(s[:2], "am") || std.sleq(s[:2], "AM") -> s[2:] elif std.sleq(s[:2], "pm") || std.sleq(s[:2], "PM") d.h += 12 -> s[2:] else err# = true -> s ;; } const time = {inst var t var c, y, ya, m, u t = 0 if inst.mon > 2 m = (inst.mon - 3) castto(std.time) else m = (inst.mon + 9) castto(std.time) y = (inst.year - 1) castto(std.time) ;; c = y / 100 ya = y - 100 * c u = (146097 * c) / 4 + \ (1461 * ya) / 4 + \ (153 * m + 2) / 5 + \ (inst.day castto(std.time)) + \ UnixJulianDiff t += (u * 24*60*60*1_000_000) t += (inst.h castto(std.time)) * 60*60*1_000_000 t += (inst.m castto(std.time)) * 60*1_000_000 t += (inst.s castto(std.time)) * 1_000_000 t += inst.us castto(std.time) -> t }