ref: bbb28d255caf1b890e4bd5dca79ae6f5d11a360c
author: Ori Bernstein <ori@eigenstate.org>
date: Thu Aug 28 11:11:09 EDT 2014
Initial commit. We don't do timezones yet.
--- /dev/null
+++ b/lib/date/Makefile
@@ -1,0 +1,12 @@
+MYRLIB=date
+MYRSRC= \
+ date.myr \
+ zoneinfo.myr \
+
+MYRFLAG=-I .
+
+include config.mk
+include mk/myr.mk
+
+check: all
+ make -C test check
--- /dev/null
+++ b/lib/date/configure
@@ -1,0 +1,52 @@
+#!/bin/sh
+
+prefix="/usr/local"
+
+for i in `seq 300`; do
+ echo "Lots of output to emulate automake... ok"
+ echo "Testing for things you'll never use... fail"
+ echo "Satisfying the fortran77 lobby... ok"
+ echo "Burning CPU time checking for the bloody obvious... ok"
+done
+echo "Automake emulated successfully"
+
+INST_ROOT='/usr/local'
+
+for arg in $*; do
+ shift 1
+ case $arg in
+ "--prefix" | "-p")
+ prefix=shift $*
+ ;;
+ --prefix=*)
+ prefix=`echo $arg | sed 's/^--prefix=//g'`
+ ;;
+ "--help" | "-h")
+ echo "Usage:"
+ echo " --prefix | -p: The prefix to install to"
+ break;
+ ;;
+ *) echo "Unrecognized argument $arg";;
+ esac
+done
+
+OS=`uname`
+
+echo export INST_ROOT=$prefix > config.mk
+case $OS in
+ *Linux*)
+ echo 'export SYS=linux' >> config.mk
+ ;;
+ *Darwin*)
+ echo 'export SYS=osx' >> config.mk
+ ;;
+ *)
+ echo 'Unknown architecture.'
+ ;;
+esac
+
+cat << EOF
+ Building with:
+ prefix=$prefix
+EOF
+
--- /dev/null
+++ b/lib/date/date.myr
@@ -1,0 +1,118 @@
+use std
+
+pkg date =
+ type date = struct
+ actual : std.time /* epoch time in microseconds */
+ tzoff : diff /* timezone offset in microseconds */
+ year : int /* year, starting at 0 (ie, 1 BCE) */
+ mon : int /* month, [1..12] */
+ day : int /* day, [1..31] */
+ wday : int /* weekday, [0..6] */
+ h : int /* hour: [0..23] */
+ m : int /* minute: [0..59] */
+ s : int /* second: [0..59] */
+ us : int /* microsecond: [0..999,999] */
+ ;;
+
+ type diff = std.time
+
+ /* 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 bfmt : (d : date, buf : byte[:] -> byte[:])
+
+ /* useful constructors */
+ const mkdate : (tm : std.time, tz : diff -> date)
+ const now : (-> date)
+ const utcnow : (-> date)
+ const localoff : (-> diff)
+ const tzoff : (tzname : byte[:] -> diff)
+
+ /* date differences */
+ const add : (d : date, dt : diff -> date)
+ const diff : (a : date, b : date -> diff)
+;;
+
+const monthbound = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ]
+const leapmonthbound = [0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ]
+const Day400y = (365*400 + 24*4 + 1)
+const Day100y = (365*100 + 24)
+const Day4y = (365*4 + 1)
+
+const now = {
+ -> utcnow()
+}
+
+const utcnow = {
+ var tm
+
+ tm = std.now()
+ std.put("tm = %l\n", tm)
+ -> mkdate(tm, 0)
+}
+
+const mkdate = {tm, off
+ var j, y, m, d
+ var t, e
+ var date
+
+ /* apply time zone offset */
+ tm += off castto(std.time)
+ t = tm % (24*60*60*1_000_000) /* time */
+ e = tm / (24*60*60*1_000_000) /* epoch days */
+
+ date.actual = tm
+
+ /* microseconds, seconds, minutes, hours */
+ date.us = (t % 1_000_000) castto(int)
+ t /= 1_000_000
+ date.s = (t % 60) castto(int)
+ t /= 60
+ date.m = (t % 60) castto(int)
+ t /= 60
+ date.h = t castto(int)
+
+ /* weekday */
+ date.wday = ((e + 4) % 7) castto(int) /* the world started on Thursday */
+ /*
+ year, month, day:
+
+ Implemented according to algorithm 199, conversions between calendar
+ date and Julian day number:
+ Robert G. Tantzen
+ Air Force Missile: Development Center, Holloman AFB, New Mex.
+
+ Lots of magic.
+ */
+ j = e + 719468
+ y = (4 * j - 1) / 146097
+ j = 4 * j - 1 - 146097 * y
+ d = j / 4
+ j = (4 * d + 3) / 1461
+ d = 4 * d + 3 - 1461 * j
+ d = (d + 4) / 4 ;
+ m = (5 * d - 3) / 153
+ d = 5 * d - 3 - 153 * m
+ d = (d + 5) / 5
+ y = 100 * y + j
+ if m < 10
+ m += 3
+ else
+ m -= 9
+ y++
+ ;;
+ date.year = y castto(int)
+ date.mon = m castto(int)
+ date.day = (d + 1) castto(int)
+ -> date
+}
+
+const ndays = {y
+ if y % 4 == 0 && (y % 100 != 0 || y % 400 == 0)
+ -> 366
+ else
+ -> 365
+ ;;
+}
--- /dev/null
+++ b/lib/date/mk/myr.mk
@@ -1,0 +1,97 @@
+ifneq ($(MYRLIB),)
+ _LIBNAME=lib$(MYRLIB).a
+endif
+
+all: subdirs $(_LIBNAME) $(MYRBIN)
+
+subdirs:
+ @for i in $(SUB); do (\
+ cd $$i && \
+ $(MAKE) || \
+ exit 1 \
+ ) || exit 1; done
+
+subdirs-clean:
+ @for i in $(SUB); do (\
+ cd $$i && \
+ $(MAKE) clean|| \
+ exit 1 \
+ ); done
+
+subdirs-install:
+ @for i in $(SUB); do (\
+ cd $$i && \
+ $(MAKE) install|| \
+ exit 1 \
+ ); done
+
+subdirs-uninstall:
+ @for i in $(SUB); do (\
+ cd $$i && \
+ $(MAKE) uninstall|| \
+ exit 1 \
+ ); done
+
+$(_LIBNAME): $(MYRSRC) $(ASMSRC)
+ myrbuild -l $(MYRLIB) $(MYRFLAG) $^
+
+$(MYRBIN): $(MYRSRC) $(ASMSRC)
+ myrbuild -b $(MYRBIN) $(MYRFLAG) $^
+
+OBJ=$(MYRSRC:.myr=.o) $(ASMSRC:.s=.o)
+USE=$(MYRSRC:.myr=.use) $(MYRLIB)
+.PHONY: clean
+clean: subdirs-clean
+ rm -f $(OBJ)
+ rm -f $(USE)
+ @if [ ! -z "$(MYRLIB)" ]; then \
+ echo rm -f $(MYRLIB); \
+ rm -f $(MYRLIB); \
+ echo rm -f lib$(MYRLIB).a; \
+ rm -f lib$(MYRLIB).a; \
+ fi
+ @if [ ! -z "$(MYRBIN)" ]; then \
+ echo rm -f $(MYRBIN); \
+ rm -f $(MYRBIN); \
+ echo rm -f lib$(MYRBIN).a; \
+ rm -f lib$(MYRBIN).a; \
+ fi
+
+install: subdirs-install $(MYRBIN) $(_LIBNAME) $(MAN)
+ @if [ ! -z "$(MYRBIN)" ]; then \
+ echo install $(MYRBIN) $(abspath $(DESTDIR)/$(INST_ROOT)/bin); \
+ mkdir -p $(abspath $(DESTDIR)/$(INST_ROOT)/bin); \
+ install $(MYRBIN) $(abspath $(DESTDIR)/$(INST_ROOT)/bin); \
+ fi
+ @if [ ! -z "$(_LIBNAME)" ]; then \
+ echo install -m 644 $(_LIBNAME) $(abspath $(DESTDIR)/$(INST_ROOT)/lib/myr); \
+ echo install -m 644 $(MYRLIB) $(abspath $(DESTDIR)/$(INST_ROOT)/lib/myr); \
+ mkdir -p $(abspath $(DESTDIR)/$(INST_ROOT)/lib/myr); \
+ install -m 644 $(_LIBNAME) $(abspath $(DESTDIR)/$(INST_ROOT)/lib/myr); \
+ install -m 644 $(MYRLIB) $(abspath $(DESTDIR)/$(INST_ROOT)/lib/myr); \
+ fi
+ @for i in $(MAN); do \
+ MANSECT=$$(echo $$i | awk -F. '{print $$NF}'); \
+ echo mkdir -p $(abspath $(DESTDIR)/$(INST_ROOT)/share/man/man$$MANSECT); \
+ echo install -m 644 $(MAN) $(abspath $(DESTDIR)/$(INST_ROOT)/share/man/man$${MANSECT}); \
+ mkdir -p $(abspath $(DESTDIR)/$(INST_ROOT)/share/man/man$$MANSECT); \
+ install -m 644 $(MAN) $(abspath $(DESTDIR)/$(INST_ROOT)/share/man/man$${MANSECT}); \
+ done \
+
+uninstall: subdirs-uninstall
+ @for i in $(MYRBIN); do \
+ echo rm -f $(abspath $(DESTDIR)/$(INST_ROOT)/bin/$$i); \
+ rm -f $(abspath $(DESTDIR)/$(INST_ROOT)/bin/$$i); \
+ done
+ @for i in $(_LIBNAME) $(MYRLIB); do \
+ echo rm -f $(abspath $(DESTDIR)/$(INST_ROOT)/lib/myr/$$i); \
+ rm -f $(abspath $(DESTDIR)/$(INST_ROOT)/lib/myr/$$i); \
+ done
+ @for i in $(MAN); do \
+ MANSECT=$$(echo $$i | awk -F. '{print $$NF}'); \
+ echo rm -f $(abspath $(DESTDIR)/$(INST_ROOT)/share/man/man$${MANSECT}/$$i); \
+ rm -f $(abspath $(DESTDIR)/$(INST_ROOT)/share/man/man$${MANSECT}/$$i); \
+ done
+
+config.mk:
+ ./configure
--- /dev/null
+++ b/lib/date/zoneinfo.myr
@@ -1,0 +1,125 @@
+use std
+
+pkg _timezone =
+ type zifile
+ const load : (file : byte[:] -> zifile#)
+;;
+
+type zifile = struct
+ time : int32[:]
+ timetype: byte[:]
+ ttinfo : ttinfo[:]
+ abbrev : byte[:]
+ leap : int32[2][:]
+ isstd : byte[:]
+ isgmt : byte[:]
+;;
+
+type ttinfo = struct
+ gmtoff : int32
+ isdst : byte
+ abbrind : byte
+;;
+
+const load = {file
+ var nisgmt
+ var nisstd
+ var nleap
+ var ntime
+ var ntype
+ var nchar
+ var i
+ var f
+ var p
+
+ /* check magic */
+ match std.slurp(file)
+ | `std.Ok d: p = d
+ | `std.Fail m:
+ std.put("unable to load zone: %s\n", m)
+ -> std.zalloc()
+ ;;
+
+ if !std.sleq(p[:4], "TZif")
+ std.put("%s is not a zone info file\n", file)
+ -> std.zalloc()
+ ;;
+
+ /* skip to data */
+ p = p[20:]
+ (nisgmt, p) = fetchbe32(p)
+ (nisstd, p) = fetchbe32(p)
+ (nleap, p) = fetchbe32(p)
+ (ntime, p) = fetchbe32(p)
+ (ntype, p) = fetchbe32(p)
+ (nchar, p) = fetchbe32(p)
+
+
+ f = std.alloc()
+ f.time = std.slalloc(ntime castto(std.size))
+ for i = 0; i < ntime; i++
+ (f.time[i], p) = fetchbe32(p)
+ ;;
+
+ f.timetype = std.slalloc(ntime castto(std.size))
+ for i = 0; i < ntime; i++
+ (f.timetype[i], p) = fetchbe8(p)
+ ;;
+
+ f.ttinfo = std.slalloc(ntype castto(std.size))
+ for i = 0; i < ntype; i++
+ p = fetchttinfo(p, &f.ttinfo[i])
+ ;;
+
+ f.abbrev = std.slalloc(nchar castto(std.size))
+ for i = 0; i < nchar; i++
+ (f.abbrev[i], p) = fetchbe8(p)
+ ;;
+
+ f.leap = std.slalloc(nleap castto(std.size))
+ for i = 0; i < nleap; i++
+ (f.leap[i][0], p) = fetchbe32(p)
+ (f.leap[i][1], p) = fetchbe32(p)
+ ;;
+
+ f.isstd = std.slalloc(nisstd castto(std.size))
+ for i = 0; i < nisstd; i++
+ (f.isstd[i], p) = fetchbe8(p)
+ ;;
+
+ f.isgmt = std.slalloc(nisgmt castto(std.size))
+ for i = 0; i < nisgmt; i++
+ (f.isgmt[i], p) = fetchbe8(p)
+ ;;
+
+
+ -> f
+}
+
+const fetchbe32 = {sl
+ var v
+
+ std.assert(sl.len >= 4, "Slice too small to fetch int32 from")
+ v = (sl[0] castto(int32)) << 24 | \
+ (sl[1] castto(int32)) << 16 | \
+ (sl[2] castto(int32)) << 8 | \
+ (sl[3] castto(int32)) << 0
+ -> (v, sl[4:])
+}
+
+const fetchbe8 = {sl
+ var v
+
+ std.assert(sl.len >= 1, "Slice too small to fetch int8 from")
+ v = sl[0]
+ -> (v, sl[1:])
+}
+
+
+const fetchttinfo = {sl, dst : ttinfo#
+ (dst.gmtoff, sl) = fetchbe32(sl)
+ (dst.isdst, sl) = fetchbe8(sl)
+ (dst.abbrind, sl) = fetchbe8(sl)
+ -> sl
+}
+