hare

The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

commit a8e619879d75b301e07586e855d679c52b36cb14
parent b6b9bfb7f072826a18b755141c9b33285e7e79e1
Author: Byron Torres <b@torresjrjr.com>
Date:   Tue, 25 Jan 2022 15:39:31 +0000

lookupzone(); timezone.zone: zone

Signed-off-by: Byron Torres <b@torresjrjr.com>

Diffstat:
Mdatetime/datetime.ha | 33++++++++-------------------------
Mtime/chrono/chronology.ha | 28++++++++++++++--------------
Mtime/chrono/timezone.ha | 58++++++++++++++++++++++++++++++++++++++++++----------------
3 files changed, 64 insertions(+), 55 deletions(-)

diff --git a/datetime/datetime.ha b/datetime/datetime.ha @@ -31,7 +31,7 @@ fn init() datetime = datetime { date = 0, time = 0, loc = chrono::local, - zone = void, + zone = chrono::zone { ... }, era = void, year = void, @@ -65,28 +65,12 @@ export fn new( zoffset: time::duration, loc: (*chrono::timezone | void), ) (datetime | errors::invalid) = { - const dt = datetime { - date = calc_epochal_from_ymd(year, month, day)?, - time = calc_time_from_hmsn(hour, min, sec, nsec)?, - loc = if (loc is void) chrono::local else loc: *chrono::timezone, - zone = void, - - era = void, - year = year, - month = month, - day = day, - isoweekyear = void, - isoweek = void, - week = void, - weekday = void, - yearday = void, - - hour = hour, - min = min, - sec = sec, - nsec = nsec, - }; - return dt; + const m = chrono::new( + calc_epochal_from_ymd(year, month, day)?, + calc_time_from_hmsn(hour, min, sec, nsec)?, + if (loc is void) chrono::local else loc: *chrono::timezone, + ); + return from_moment(m); }; // Returns a [[datetime]] of the immediate system time @@ -94,8 +78,7 @@ export fn now() datetime = { // TODO: should the clock and timezone be choosable? const i = time::now(time::clock::REALTIME); const m = chrono::from_instant(i, chrono::local); - const dt = from_moment(m); - return dt; + return from_moment(m); }; // Creates a copy of a [[datetime]] diff --git a/time/chrono/chronology.ha b/time/chrono/chronology.ha @@ -10,10 +10,15 @@ export type moment = struct { time: time::duration, // The timezone used for interpreting a moment's date and time + // + // TODO: make locality nullable? would make moment "{ ... }" initable + // without a "new" function, though all functions would have to default + // to a particular locality, which might be bad design considering we + // don't just support UTC_Z. loc: locality, - // The cached temporal zone this moment observes - zone: (zone | void), + // The current [[zone]] this moment observes + zone: zone, }; // An ordinal day (on Earth or otherwise) since the Hare epoch (zeroth day) @@ -22,27 +27,22 @@ export type epochal = i64; // Creates a new [[moment]] export fn new(date: epochal, time: time::duration, loc: locality) moment = { - return moment { + const m = moment { date = date, time = time, loc = loc, - zone = void, + zone = zone { ... }, }; + lookupzone(&m); + return m; }; // Creates a new [[moment]] from a [[time::instant]] in a [[locality]] export fn from_instant(i: time::instant, loc: locality) moment = { const daysec = (loc.daylength / time::SECOND); - const m = moment { - date = i.sec / daysec, - time = ( - (i.sec % daysec) * time::SECOND - + i.nsec * time::NANOSECOND - ), - loc = loc, - zone = void, - }; - return m; + const d = i.sec / daysec; + const t = (i.sec % daysec) * time::SECOND + i.nsec * time::NANOSECOND; + return new(d, t, loc); }; // Creates a new [[time::instant]] from a [[moment]] diff --git a/time/chrono/timezone.ha b/time/chrono/timezone.ha @@ -90,30 +90,56 @@ export fn localize(m: moment) moment = { return m; }; -// Finds and returns a [[moment]]'s currently observed zone +// Finds, sets and returns a [[moment]]'s currently observed zone export fn lookupzone(m: *moment) zone = { - if (m.zone is zone) { - return m.zone as zone; - }; - if (len(m.loc.zones) == 0) { - // TODO: redesign to avoid this? - abort("timezones should have at least one zone"); + // TODO: what to do? not ideal to assume UTC_Z + abort("lookup(): timezones should have at least one zone"); }; + if (len(m.loc.zones) == 1) { - const z = m.loc.zones[0]; - m.zone = z; - return z; + m.zone = m.loc.zones[0]; + return m.zone; + }; + + const inst = to_instant(*m); + + if ( + len(m.loc.transitions) == 0 + || time::compare(inst, m.loc.transitions[0].when) == -1 + ) { + // TODO: special case + abort("lookupzone(): time is before known transitions"); + }; + + let lo = 0z; + let hi = len(m.loc.transitions); + for (hi - lo > 1) { + const mid = lo + (hi - lo) / 2; + const middle = m.loc.transitions[mid].when; + switch (time::compare(inst, middle)) { + case -1 => + hi = mid; + case 0 => + lo = mid; break; + case 1 => + lo = mid; + case => + abort("Unreachable"); + }; }; - // TODO: search through m.loc.trans using m.date and m.time - if (len(m.loc.zones) > 1) { - const z = m.loc.zones[0]; - m.zone = z; - return z; + m.zone = m.loc.zones[m.loc.transitions[lo].zoneindex]; + + // if we've reached the end of the locality's transitions, try its + // posix_extend string + // + // TODO: important + if (lo == len(m.loc.transitions) - 1 && m.loc.posix_extend != "") { + void; }; - abort("TODO"); + return m.zone; }; // Creates a [[timezone]] with a single [[zone]], useful for fixed offsets