shithub: mc

Download patch

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