ref: f7228d204a9cbe40f7b6286ba8987ef65691bfbd
parent: 19e038b0670828810453c284589469c6520aa7d9
author: Ori Bernstein <ori@eigenstate.org>
date: Mon Sep 21 18:18:08 EDT 2015
Add period addition/subtraction.
--- a/lib/date/date.myr
+++ b/lib/date/date.myr
@@ -9,18 +9,17 @@
const tozone : (d : instant, zone : byte[:] -> instant)
const mkinstant : (tm : std.time, zone : byte[:] -> instant)
- const localoff : (tm : std.time -> delta)
- const tzoff : (tzname : byte[:], tm : std.time -> delta)
+ const localoff : (tm : std.time -> duration)
+ const tzoff : (tzname : byte[:], tm : std.time -> duration)
const isleap : (d : instant -> bool)
/* date differences */
- const add : (d : instant, dt : delta -> instant)
- const sub : (d : instant, dt : delta -> instant)
- const delta : (a : instant, b : instant -> delta)
- /*
- const duradd : (d : instant, dt : period -> instant)
- const dursub : (d : instant, dt : period -> instant)
- */
+ const add : (d : instant, dt : duration -> instant)
+ const sub : (d : instant, dt : duration -> instant)
+ const addperiod : (d : instant, dt : period -> instant)
+ const subperiod : (d : instant, dt : period -> instant)
+
+ const duration : (a : instant, b : instant -> duration)
;;
const Days400y = 365*400 + 4*25 - 3
@@ -71,13 +70,10 @@
inst.us = (t % 1_000_000) castto(int)
t /= 1_000_000
inst.s = (t % 60) castto(int)
- std.assert(inst.s >= 0, "inst.s negative??\n")
t /= 60
inst.m = (t % 60) castto(int)
- std.assert(inst.m >= 0, "inst.m negative??\n")
t /= 60
inst.h = t castto(int)
- std.assert(inst.h >= 0, "inst.h negative??\n")
/* weekday */
inst.wday = ((e + 4) % 7) castto(int) /* the world started on Thursday */
@@ -152,7 +148,58 @@
-> mkinstant(d.actual - (dt castto(std.time)), d.tzname)
}
-const delta = {a, b
- -> (b.actual - a.actual) castto(delta)
+const addperiod = {inst, p
+ match p
+ | `Year y: inst.year += y
+ | `Month m: inst.mon += m
+ | `Day d: inst.day += d
+ | `Hour h: inst.h += h
+ | `Minute m: inst.m += m
+ | `Second s: inst.s += s
+ ;;
+ -> mkinstant(recalc(inst), inst.tzname)
}
+const subperiod = {inst, p
+ match p
+ | `Year y: inst.year -= y
+ | `Month m: inst.mon -= m
+ | `Day d: inst.day -= d
+ | `Hour h: inst.h -= h
+ | `Minute m: inst.m -= m
+ | `Second s: inst.s -= s
+ ;;
+ -> mkinstant(recalc(inst), inst.tzname)
+}
+
+const duration = {a, b
+ -> (b.actual - a.actual) castto(duration)
+}
+
+const recalc = {inst
+ var c, ya, j, tm
+ var year, mon, day
+ var h, m, s, us
+
+ year = inst.year castto(std.time)
+ mon = inst.mon castto(std.time)
+ day = inst.day castto(std.time)
+ h = inst.h castto(std.time)
+ m = inst.m castto(std.time)
+ s = inst.s castto(std.time)
+ us = inst.us castto(std.time)
+
+ if m > 2
+ mon -= 3
+ else
+ mon += 9
+ year -= 1
+ ;;
+ c = year / 100
+ ya = year - 100 * c
+ j = (c*Days400y/4 + Days4y*ya/4 + (153*mon+2)/5 + day)
+ j -= 719469
+ tm = j * DayUsec
+ tm += (3600*h + 60*m + s)*1_000_000 + us
+ -> tm
+}
--- a/lib/date/test/fmt.myr
+++ b/lib/date/test/fmt.myr
@@ -3,11 +3,13 @@
const main = {
var buf : byte[1024]
- var d
+ var d, s
/* epoch */
d = date.mkinstant(0, "")
eq("1970-1-01 00:00:00 +0000", std.bfmt(buf[:], "{D}", d))
+ d = date.mkinstant(24*3600*1_000_000, "")
+ eq("1970-1-02 00:00:00 +0000", std.bfmt(buf[:], "{D}", d))
/* epoch + 12 hours */
d = date.mkinstant(12*3600*1_000_000, "")
@@ -32,6 +34,35 @@
/* date in the bc */
d = date.mkinstant(-70000000000*1_000_000, "")
eq("-249-11-19 19:33:20 +0000", std.bfmt(buf[:], "{D}", d))
+
+ /* test addition and subtraction of dates */
+ d = date.mkinstant(-1, "")
+ d = date.addperiod(d, `date.Hour 1)
+ eq("1970-1-01 00:59:59 +0000", std.bfmt(buf[:], "{D}", d))
+
+ d = date.mkinstant(0, "")
+ d = date.addperiod(d, `date.Hour 24)
+ eq("1970-1-02 00:00:00 +0000", std.bfmt(buf[:], "{D}", d))
+
+ d = date.mkinstant(0, "")
+ d = date.addperiod(d, `date.Day 1)
+ eq("1970-1-02 00:00:00 +0000", std.bfmt(buf[:], "{D}", d))
+
+ d = date.subperiod(d, `date.Day 1)
+ eq("1970-1-01 00:00:00 +0000", std.bfmt(buf[:], "{D}", d))
+
+ d = date.subperiod(d, `date.Year 1)
+ eq("1969-1-01 00:00:00 +0000", std.bfmt(buf[:], "{D}", d))
+
+ d = date.mkinstant(12*3601*1_000_000, "")
+ for var i = 0; i < 50; i++
+ d = date.addperiod(d, `date.Day 1)
+ d = date.addperiod(d, `date.Second 1)
+ s = std.fmt("1970-{}-{p=0,w=2} 12:{p=0,w=2}:{p=0,w=2} +0000", \
+ (i+1)/31 + 1, (i+1)%31+1, (i+13)/60, (i+13)%60)
+ eq(s, std.bfmt(buf[:], "{D}", d))
+ std.slfree(s)
+ ;;
}
const eq = {expected, actual
--- a/lib/date/types.myr
+++ b/lib/date/types.myr
@@ -3,7 +3,7 @@
pkg date =
type instant = struct
actual : std.time /* epoch time in microseconds */
- tzoff : delta /* timezone offset in microseconds */
+ tzoff : duration /* timezone offset in microseconds */
year : int /* year, starting at 0 (ie, 1 BCE) */
mon : int /* month, [1..12] */
day : int /* day, [1..31] */
@@ -16,12 +16,12 @@
_tzbuf : byte[32] /* current time zone name storage */
;;
- type delta = std.time
+ type duration = std.time
type period = union
- `Day int
- `Month int
`Year int
+ `Month int
+ `Day int
`Hour int
`Minute int
`Second int
--- a/lib/date/zoneinfo.myr
+++ b/lib/date/zoneinfo.myr
@@ -5,7 +5,7 @@
pkg _zoneinfo =
type zifile
- const findtzoff : (tz : byte[:], tm : std.time -> date.delta)
+ const findtzoff : (tz : byte[:], tm : std.time -> date.duration)
const load : (file : byte[:] -> zifile#)
const free : (f : zifile# -> void)
;;
@@ -70,7 +70,7 @@
;;
ds = zone.ttinfo[zone.timetype[i]].gmtoff
free(zone)
- -> (ds castto(date.delta)) * 1_000_000
+ -> (ds castto(date.duration)) * 1_000_000
}
const load = {file