shithub: mc

Download patch

ref: c7f1a4d7d10daa2f561535ab68df000e200d0e5b
parent: 7e02923fe7e9abd65a9b039a832ca593075f8132
author: Ori Bernstein <ori@eigenstate.org>
date: Fri Aug 29 11:38:31 EDT 2014

Add time formatting support.

--- a/lib/date/Makefile
+++ b/lib/date/Makefile
@@ -1,6 +1,7 @@
 MYRLIB=date
 MYRSRC= \
 	date.myr \
+	fmt.myr \
 	types.myr \
 	zoneinfo.myr \
 
--- a/lib/date/date.myr
+++ b/lib/date/date.myr
@@ -3,25 +3,21 @@
 use "zoneinfo.use"
 
 pkg date =
-	/* date i/o */
-	const parse	: (d : byte[:]	-> date)
-	const parsefmt	: (fmt : byte[:], d : byte[:]	-> date)
-	const parsez	: (d : byte[:], tz : byte[:]	-> date)
-	const fmt	: (d : date	-> byte[:])
-	const fmtymd	: (d : date	-> byte[:])
-	const bfmt	: (buf : byte[:], d : date	-> std.size)
-	const bfmtymd	: (buf : byte[:], d : date	-> std.size)
-
 	/* useful constructors */
-	const mkdate	: (tm : std.time, tz : diff -> date)
-	const now	: (tz : byte[:] -> date)
-	const utcnow	: (-> date)
-	const localoff	: (-> diff)
-	const tzoff	: (tzname : byte[:]	-> diff)
+	const utcnow	: (-> instant)
+	const now	: (tz : byte[:] -> instant)
+	const mkdate	: (tm : std.time, zone : byte[:] -> instant)
 
+	const localoff	: (tm : std.time -> diff)
+	const tzoff	: (tzname : byte[:], tm : std.time	-> diff)
+	const isleap	: (d : instant	-> bool)
+
 	/* date differences */
-	const add	: (d : date, dt : diff	-> date)
-	const diff	: (a : date, b : date -> diff)
+	const add	: (d : instant, dt : diff	-> instant)
+	const sub	: (d : instant, dt : diff	-> instant)
+	const diff	: (a : instant, b : instant	-> diff)
+	const duradd	: (d : instant, dt : duration	-> instant)
+	const dursub	: (d : instant, dt : duration	-> instant)
 ;;
 
 const Unix2Julian	= 719468
@@ -28,41 +24,33 @@
 const Days400y	= 365*400 + 4*25 - 3
 const Days4y	= 365*4 + 1
 
-const fmt = {d
-	-> std.fmt("%04i-%02i-%02i %i:%i:%i", d.year, d.mon, d.day, d.h, d.m, d.s)
+const utcnow = {
+	-> mkdate(std.now(), "")
 }
 
-const fmtymd = {d
-	-> std.fmt("%04i-%02i-%02i", d.year, d.mon, d.day)
-}
-
-const bfmt = {buf, d
-	-> std.bfmt(buf, "%04i-%02i-%02i %i:%i:%i", d.year, d.mon, d.day, d.h, d.m, d.s)
-}
-
-const bfmtymd = {buf, d
-	-> std.bfmt(buf, "%04i-%02i-%02i", d.year, d.mon, d.day)
-}
-
 const now = {tz : byte[:]
 	var tm
 
 	tm = std.now()
-	-> mkdate(tm, _zoneinfo.findtzoff(tz, tm))
+	-> mkdate(tm, tz)
 }
 
-const utcnow = {
-	-> mkdate(std.now(), 0)
-}
-
-const mkdate = {tm, off
+const mkdate = {tm, tz 
 	var j, y, m, d
 	var t, e
 	var date
+	var off
 
 	date.actual = tm
+	/* time zones */
+	std.assert(tz.len <= date._tzbuf.len, "time zone name too long\n")
+	off =_zoneinfo.findtzoff(tz, tm) 
 	date.tzoff = off
+	std.slcp(date._tzbuf[:tz.len], tz)
+	date.tzname = date._tzbuf[:tz.len]
 	tm += off castto(std.time)
+
+	/* break up time */
 	t = tm % (24*60*60*1_000_000)	/* time */
 	e = tm / (24*60*60*1_000_000)	/* epoch days */
 
@@ -78,8 +66,9 @@
 
 	/* weekday */
 	date.wday = ((e + 4) % 7) castto(int)	/* the world started on Thursday */
+
 	/*
-	year, month, day: 
+	split up year, month, day.
 
 	Implemented according to "Algorithm 199, conversions between calendar 
 	date and Julian day number", Robert G. Tantzen, Air Force Missile Development
@@ -110,10 +99,28 @@
 	-> date
 }
 
-const ndays = {y
-	if y % 4 == 0 && (y % 100 != 0 || y % 400 == 0)
-		-> 366
-	else
-		-> 365
-	;;
+const localoff = {tm
+	-> _zoneinfo.findtzoff("local", tm)
 }
+
+const tzoff = {tz, tm
+	-> _zoneinfo.findtzoff(tz, tm)
+}
+
+
+const isleap = {d
+	-> d.year % 4 == 0 && (d.year % 100 != 0 || d.year % 400 == 0)
+}
+
+const add  = {d, dt
+	-> mkdate(d.actual + (dt castto(std.time)), d.tzname)
+}
+
+const sub  = {d, dt
+	-> mkdate(d.actual - (dt castto(std.time)), d.tzname)
+}
+
+const diff = {a, b
+	-> (b.actual - a.actual) castto(diff)
+}
+
--- /dev/null
+++ b/lib/date/fmt.myr
@@ -1,0 +1,112 @@
+use std
+use "types.use"
+
+pkg date = 
+	const fmt	: (d : instant, time : bool	-> byte[:])
+	const bfmt	: (buf : byte[:], d : instant, time : bool	-> std.size)
+	const ftime	: (f : byte[:], d : instant	-> byte[:])
+	const bftime	: (buf : byte[:], f : byte[:], d : instant	-> std.size)
+;;
+
+const Datetimefmt	= "%Y-%m-%d %h:%m:%s %z"
+const Timefmt	= "%h:%m:%s %z"
+const Datefmt	= "%Y-%m-%d %z"
+
+const fmt = {d, time
+	if time
+		-> ftime(Datetimefmt, d)
+	else
+		-> ftime(Datefmt, d)
+	;;
+}
+
+const bfmt = {buf, d, time
+	if time
+		-> bftime(buf, Datetimefmt, d)
+	else
+		-> bftime(buf, Datefmt, d)
+	;;
+}
+
+const ftime = {f, d
+	var buf
+	var sz
+
+	buf = std.slalloc(2048)
+	sz = bftime(buf, f, d)
+	-> buf[:sz]
+}
+
+const abbrevday = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
+const fullday = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
+const abbrevmon = ["NONE", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
+const fullmon = ["NONE", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]
+
+const bftime = {buf, f, d
+	var c
+	var o
+	
+	o = 0
+	while f.len != 0
+		(c, f) = std.striter(f)
+		if c == '%'
+			(c, f) = std.striter(f)
+			match c
+			| 'a':	o += std.bfmt(buf[o:], "%s", abbrevday[d.day])
+			| 'A':	o += std.bfmt(buf[o:], "%s", fullday[d.day])
+			| 'b':	o += std.bfmt(buf[o:], "%s", abbrevmon[d.mon])
+			| 'B':	o += std.bfmt(buf[o:], "%s", fullmon[d.mon])
+			| 'c':	o += bftime(buf[o:], "%Y-%m-%d", d)
+			| 'C':	o += std.bfmt(buf[o:], "%02i", d.year % 100)
+			| 'd':	o += std.bfmt(buf[o:], "%02i", d.day)
+			| 'D':	o += std.bfmt(buf[o:], "%m/%d/%y (wtf america)", d.mon, d.day, d.year)
+			| 'e':	o += std.bfmt(buf[o:], "%2i", d.day)
+			| 'F':	o += std.bfmt(buf[o:], "%y-%m-%d", d.year, d.mon, d.day)
+			/*
+			| 'G':	o += std.bfmt(buf[o:], ...?
+			| 'g':
+			*/
+			| 'h':	o += std.bfmt(buf[o:], "%s", abbrevmon[d.mon])
+			| 'H':	o += std.bfmt(buf[o:], "%02i", d.h)
+			| 'I':	o += std.bfmt(buf[o:], "%02i", d.h % 12)
+			| 'j':	o += std.bfmt(buf[o:], "year day... unimplemented.")
+			| 'k':	o += std.bfmt(buf[o:], "%i", d.h)
+			| 'l':	o += std.bfmt(buf[o:], "%i", d.h % 12)
+			| 'm':	o += std.bfmt(buf[o:], "%i", d.mon)
+			| 'M':	o += std.bfmt(buf[o:], "%i", d.m)
+			| 'n':	o += std.bfmt(buf[o:], "\n")
+			| 'O':	o += std.bfmt(buf[o:], "unsupported %O")
+			| 'p':	o += std.bfmt(buf[o:], "%s", ["AM", "PM"][d.h/12])
+			| 'P':	o += std.bfmt(buf[o:], "%s", ["am", "pm"][d.h/12])
+			| 'r':	o += bftime(buf[o:], "%H:%M:%S %P", d) 
+			| 'R':	o += bftime(buf[o:], "%H:%M %P", d)
+			| 's':	o += std.bfmt(buf[o:], "%l", d.actual)
+			| 'S':	o += std.bfmt(buf[o:], "%i", d.s)
+			| 't':	o += std.bfmt(buf[o:], "\t")
+			| 'u':	o += std.bfmt(buf[o:], "%i", d.wday)
+			| 'U':	o += std.bfmt(buf[o:], "week number... unimplemented.")
+			| 'x':	o += bftime(buf[o:], Datefmt, d)
+			| 'X':	o += bftime(buf[o:], Timefmt, d)
+			| 'y':	o += std.bfmt(buf[o:], "%i", d.year)
+			| 'Y':	o += std.bfmt(buf[o:], "%i", d.year % 100)
+			| 'z':	o += timezone(buf[o:], d.tzoff)
+			| 'Z':	o += std.bfmt(buf[o:], "%s", d.tzname)
+			| '%':	o += std.bfmt(buf[o:], "%%")
+			;;
+		else
+			o += std.bfmt(buf[o:], "%c", c)
+		;;
+	;;
+	-> o
+}
+
+const timezone = {buf, off
+	var h, m
+
+	h = off % 3600
+	m = off / 3600
+	if off < 0
+		off = -off
+	;;
+	-> std.bfmt(buf, "%i:%i", h, m)
+}
--- /dev/null
+++ b/lib/date/parse.myr
@@ -1,0 +1,11 @@
+use std
+use "date.use"
+
+pkg date =
+	/* date i/o */
+	const parse	: (d : byte[:]	-> instant)
+	const parsefmt	: (fmt : byte[:], d : byte[:]	-> instant)
+	const parsez	: (d : byte[:], tz : byte[:]	-> instant)
+;;
+
+
--- a/lib/date/types.myr
+++ b/lib/date/types.myr
@@ -1,7 +1,7 @@
 use std
 
 pkg date = 
-	type date = struct
+	type instant = struct
 		actual	: std.time	/* epoch time in microseconds */
 		tzoff	: diff	/* timezone offset in microseconds */
 		year	: int	/* year, starting at 0 (ie, 1 BCE) */
@@ -12,7 +12,18 @@
 		m	: int	/* minute: [0..59] */
 		s	: int	/* second: [0..59] */
 		us	: int	/* microsecond: [0..999,999] */
+		tzname	: byte[:]	/* current time zone name */
+		_tzbuf	: byte[32]	/* current time zone name storage */
 	;;
 
 	type diff = std.time
+
+	type duration = union
+		`Day	int
+		`Month	int
+		`Year	int
+		`Hour	int
+		`Minute	int
+		`Second	int
+	;;
 ;;
--- a/lib/date/zoneinfo.myr
+++ b/lib/date/zoneinfo.myr
@@ -24,19 +24,39 @@
 	abbrind	: byte
 ;;
 
+const zonepath = [
+	"/usr/share/zoneinfo",
+	"/share/zoneinfo",
+	"/etc/zoneinfo"
+]
+
 const findtzoff = {tz, tm
 	var path
 	var zone
 	var cur
+	var sb
 	var ds
 	var i
 
 	/* load zone */
-	match std.getenv("ZI")
-	| `std.Some zi:	path = zi
-	| `std.None:	path = "/etc/localtime"
+	if std.sleq(tz, "") || std.sleq(tz, "UTC")
+		-> 0
+	elif std.sleq(tz, "local")
+		path = std.sldup("/etc/localtime")
+	else
+		for z in zonepath
+			path = std.pathcat(z, tz)
+			if std.stat(path, &sb) == 0
+				goto found
+			;;
+			std.slfree(path)
+		;;
+		std.slfree(path)
+		-> 0
 	;;
+:found
 	zone = load(path)
+	std.slfree(path)
 
 	/* find applicable gmt offset */
 	cur = (tm / 1_000_000) castto(int32)
@@ -154,4 +174,3 @@
 	(dst.abbrind, sl) = fetchbe8(sl)
 	-> sl
 }
-