use fmt; use time; use time::date; use time::chrono; use os; use strconv; use strings; use getopt; type parseerror = !strconv::error; export fn main() void = { const cmd = getopt::parse(os::args, "discord relative timestamp generator", ('a', "date", "Absolute date (this option is exclusive any other options will be ignored)"), ('d', "days", "Number of days"), ('w', "weeks", "Number of weeks"), "m[:s]", ); defer getopt::finish(&cmd); let days: time::duration = 0; let weeks: time::duration = 0; for (let opt .. cmd.opts) { switch (opt.0) { case 'a' => match (abs(opt.1)) { case let i: i64 => printdistamp(i); return; case let e: chrono::tzdberror => fmt::fatal(chrono::strerror(e)); case let e: date::parsefail => let s = strings::concat(date::strerror(e), "\n", "Date format must be 'year-month-day hour:minute:second'"); defer free(s); fmt::errorln(s)!; return; case let e: date::error => fmt::fatal(date::strerror(e)); }; case 'w' => weeks = match (toweeks(opt.1)) { case let i: time::duration => yield i; case let e: strconv::error => fmt::fatal(strconv::strerror(e)); }; case 'd' => days = match (todays(opt.1)) { case let d: time::duration => yield d; case let e: parseerror => fmt::fatal(strerror(e)); }; case => abort(); }; }; if (len(cmd.args) > 1) { os::exit(os::status::FAILURE); }; let li = match (parsemainargs(cmd.args)) { case let i: time::instant => yield i; case let e: parseerror => fmt::fatal(strerror(e)); }; li = time::add(li, days); li = time::add(li, weeks); printdistamp(time::unix(li)); }; fn printdistamp(i: i64) void = { fmt::printfln("", i)!; }; fn abs(s: str) (i64 | date::error | chrono::tzdberror) = { let v = date::newvirtual(); v.vloc = chrono::tz("Europe/Paris")?; v.zoff = date::zflag::LAP_EARLY | date::zflag::GAP_END; date::parse(&v, "%Y-%m-%d %T", s)?; v.nanosecond = 0; let d = date::realize(v, chrono::LOCAL)?; //date::format(os::stderr, "%Y-%m-%d %T %L", &d)!; return time::unix(*(&d: *time::instant)); }; fn parsemainargs(args: []str) (time::instant | parseerror) = { return if (len(args) == 1) { let timestr = args[0]; let i = time::now(time::clock::REALTIME); let spl = strings::split(timestr, ":"); defer free(spl); yield if (len(spl) > 2) { fmt::fatal("Duration format: m or m:s"); } else { yield parsetime(i, spl)?; }; } else { yield time::now(time::clock::REALTIME); }; }; fn strerror(e: parseerror) str = { return strconv::strerror(e); }; fn parsetime(clk: time::instant, spl: []str) (time::instant | parseerror) = { return if (len(spl) == 2) { let m = strconv::stoi64(spl[0])?; let s = strconv::stoi64(spl[1])?; let d = (m * time::MINUTE) + (s * time::SECOND); yield time::add(clk, d); } else { let m = strconv::stoi64(spl[0])?; let d = m * time::MINUTE; yield time::add(clk, d); }; }; fn todays(days: str) (time::duration | parseerror) = { let d = strconv::stoi(days)?; return d * 24 * time::HOUR; }; fn toweeks(weeks: str) (time::duration | parseerror) = { let d = strconv::stoi(weeks)?; return d * 7 * 24 * time::HOUR; };