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:
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