hare

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

commit 7434a99d9688f5069aec10a6a1a3667ed07c1037
parent dd9d2af79b98311bf3e25e68dcc18dc1097d424b
Author: Byron Torres <b@torresjrjr.com>
Date:   Wed, 11 Oct 2023 22:47:15 +0100

time::chrono: complete utc timescale conversion

Also tidy, drop static.

Fixes: https://todo.sr.ht/~sircmpwn/hare/642
Signed-off-by: Byron Torres <b@torresjrjr.com>

Diffstat:
Mtime/chrono/timescale.ha | 227++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------------
1 file changed, 144 insertions(+), 83 deletions(-)

diff --git a/time/chrono/timescale.ha b/time/chrono/timescale.ha @@ -86,23 +86,16 @@ export const tai: timescale = timescale { }; fn tai_conv(ts: *timescale, i: time::instant) ([]time::instant | void) = { - static let buf = [time::instant { ... }]; + let ret: []time::instant = []; switch (ts) { case &tai => - buf[0] = i; - return buf; + append(ret, i); + return ret; case => return void; }; }; -// TODO: Write proper conversion functions for all timescales. -// -// Ticket: https://todo.sr.ht/~sircmpwn/hare/642 -// -// For UTC, conversion functions are to return two or no instants, depending on -// any leap second events, and use a proper leap second table. See leapsec.ha. - // Coordinated Universal Time // @@ -122,10 +115,11 @@ export const utc: timescale = timescale { }; fn utc_convto(ts: *timescale, i: time::instant) ([]time::instant | void) = { - static let buf = [time::instant { ... }]; + let ret: []time::instant = []; switch (ts) { case &utc => - buf[0] = i; + append(ret, i); + return ret; case &tai => if (!utc_isinitialized) { match (init_utc_leapsecs()) { @@ -136,28 +130,81 @@ fn utc_convto(ts: *timescale, i: time::instant) ([]time::instant | void) = { }; }; - const idx = lookup_leaps(&utc_leapsecs, time::unix(i)); - const ofst = utc_leapsecs[idx].1; - - if (time::unix(i) == utc_leapsecs[idx].0) { - void; + const firstleap = utc_leapsecs[0]; // TODO: no leapsecs loaded + if (time::compare(i, time::from_unix(firstleap.0)) < 0) { + append(ret, time::instant { + sec = i.sec + firstleap.1, + nsec = i.nsec, + }); + return ret; }; - buf[0] = time::instant { - sec = i.sec + 37, - nsec = i.nsec, + for (let idx = len(utc_leapsecs) - 1; idx >= 0 ; idx -= 1) { + const leap = utc_leapsecs[idx]; + const leapsecond = time::from_unix(leap.0); + const leapoffset = leap.1; + const diff = time::diff(leapsecond, i); + + const prevleapoffset = + if (idx == 0) 0i64 else utc_leapsecs[idx - 1].1; + const offsetdiff = + (leapoffset - prevleapoffset) * time::SECOND; + + // case of positive leap second (UTC repeats a second) + if (offsetdiff >= 0) { + if (diff >= 0) { + append(ret, time::instant { + sec = i.sec + leapoffset, + nsec = i.nsec, + }); + return ret; + }; + + if (diff >= -offsetdiff && diff < 0) { + append(ret, [ + time::instant { + sec = i.sec + prevleapoffset, + nsec = i.nsec, + }, + time::instant { + sec = i.sec + leapoffset, + nsec = i.nsec, + }, + ]...); + return ret; + }; + + continue; + }; + + // case of negative leap second (UTC skips a second) + if (offsetdiff < 0) { + if (diff >= 0) { + append(ret, time::instant { + sec = i.sec + leapoffset, + nsec = i.nsec, + }); + return ret; + }; + + if (diff >= offsetdiff && diff < 0) { + return ret; + }; + + continue; + }; }; case => return void; }; - return buf; }; fn utc_convfrom(ts: *timescale, i: time::instant) ([]time::instant | void) = { - static let buf = [time::instant { ... }]; + let ret: []time::instant = []; switch (ts) { case &utc => - buf[0] = i; + append(ret, i); + return ret; case &tai => if (!utc_isinitialized) { match (init_utc_leapsecs()) { @@ -168,44 +215,55 @@ fn utc_convfrom(ts: *timescale, i: time::instant) ([]time::instant | void) = { }; }; - const idx = lookup_leaps(&utc_leapsecs, time::unix(i)); - const ofst = utc_leapsecs[idx].1; - - if (time::unix(i) == utc_leapsecs[idx].0) { - void; + const firstleap = utc_leapsecs[0]; // TODO: no leapsecs loaded + if (time::compare(i, time::from_unix(firstleap.0 + firstleap.1)) < 0) { + append(ret, time::instant { + sec = i.sec - firstleap.1, + nsec = i.nsec, + }); + return ret; }; - buf[0] = time::instant { - sec = i.sec - 37, - nsec = i.nsec, + for (let idx = len(utc_leapsecs) - 1; idx >= 0 ; idx -= 1) { + const leap = utc_leapsecs[idx]; + const leapsecond = time::from_unix(leap.0 + leap.1); + const leapoffset = leap.1; + const diff = time::diff(leapsecond, i); + + const prevleapoffset = + if (idx == 0) 10i64 else utc_leapsecs[idx - 1].1; + const offsetdiff + = (leapoffset - prevleapoffset) * time::SECOND; + + // case of positive leap second (UTC repeats a second) + if (offsetdiff >= 0) { + if (diff >= -offsetdiff) { + append(ret, time::instant { + sec = i.sec - leapoffset, + nsec = i.nsec, + }); + return ret; + }; + + continue; + }; + + // case of negative leap second (UTC skips a second) + if (offsetdiff < 0) { + if (diff >= 0) { + append(ret, time::instant { + sec = i.sec - leapoffset, + nsec = i.nsec, + }); + return ret; + }; + + continue; + }; }; case => return void; }; - return buf; -}; - -fn lookup_leaps(list: *[](i64, i64), t: i64) size = { - let lo = 0z, hi = len(list); - for (hi - lo > 1) { - const mid = lo + (hi - lo) / 2; - const middle = list[mid].0; - const cmp = time::compare( - time::from_unix(t), - time::from_unix(middle), - ); - switch (cmp) { - case -1 => - hi = mid; - case 0 => - lo = mid; break; - case 1 => - lo = mid; - case => - abort("Unreachable"); - }; - }; - return lo; }; @@ -226,29 +284,31 @@ export const gps: timescale = timescale { def GPS_OFFSET: time::duration = -19 * time::SECOND; fn gps_convto(ts: *timescale, i: time::instant) ([]time::instant | void) = { - static let buf = [time::instant { ... }]; + let ret: []time::instant = []; switch (ts) { case &gps => - buf[0] = i; + append(ret, i); + return ret; case &tai => - buf[0] = time::add(i, -GPS_OFFSET); + append(ret, time::add(i, -GPS_OFFSET)); + return ret; case => return void; }; - return buf; }; fn gps_convfrom(ts: *timescale, i: time::instant) ([]time::instant | void) = { - static let buf = [time::instant { ... }]; + let ret: []time::instant = []; switch (ts) { case &gps => - buf[0] = i; + append(ret, i); + return ret; case &tai => - buf[0] = time::add(i, GPS_OFFSET); + append(ret, time::add(i, GPS_OFFSET)); + return ret; case => return void; }; - return buf; }; @@ -269,30 +329,32 @@ export const tt: timescale = timescale { def TT_OFFSET: time::duration = 32184 * time::MILLISECOND; // 32.184 seconds fn tt_convto(ts: *timescale, i: time::instant) ([]time::instant | void) = { - static let buf = [time::instant { ... }]; + let ret: []time::instant = []; switch (ts) { case &tt => - buf[0] = i; + append(ret, i); + return ret; case &tai => - buf[0] = time::add(i, -TT_OFFSET); + append(ret, time::add(i, -TT_OFFSET)); + return ret; case => return void; }; - return buf; }; fn tt_convfrom(ts: *timescale, i: time::instant) ([]time::instant | void) = { - static let buf = [time::instant { ... }]; + let ret: []time::instant = []; switch (ts) { case &tt => - buf[0] = i; + append(ret, i); + return ret; case &tai => - buf[0] = time::add(i, TT_OFFSET); + append(ret, time::add(i, TT_OFFSET)); + return ret; case => return void; }; - return buf; }; // Arthur David Olson had expressed support for Martian time in his timezone @@ -330,11 +392,11 @@ def DELTA_MARSEPOCH_JANSIX: time::duration = 44796 * 24 * time::HOUR; def DELTA_JANSIX_ADJUSTMENT: time::duration = 82944 * time::MILLISECOND; fn mtc_convto(ts: *timescale, i: time::instant) ([]time::instant | void) = { - static let buf = [time::instant { ... }]; + let ret: []time::instant = []; switch (ts) { case &mtc => - buf[0] = i; - return buf; + append(ret, i); + return ret; case &tai => // Change epoch from that of the Mars Sol Date // to the Earth-Mars convergence date 2000 Jan 6th. @@ -352,20 +414,19 @@ fn mtc_convto(ts: *timescale, i: time::instant) ([]time::instant | void) = { // Get the TAI time. // assertion since TT and TAI are continuous. - const ts = tt.convto(&tai, i) as []time::instant; - - return ts; + append(ret, (tt.convto(&tai, i) as []time::instant)[0]); + return ret; case => - void; + return void; }; - }; fn mtc_convfrom(ts: *timescale, i: time::instant) ([]time::instant | void) = { - static let buf = [time::instant { ... }]; + let ret: []time::instant = []; switch (ts) { case &mtc => - buf[0] = i; + append(ret, i); + return ret; case &tai => // Get the "Terrestrial Time". // assertion since TT and TAI are continuous. @@ -383,9 +444,9 @@ fn mtc_convfrom(ts: *timescale, i: time::instant) ([]time::instant | void) = { i = time::add(i, -DELTA_JANSIX_ADJUSTMENT); // Change epoch to that of the Mars Sol Date. - buf[0] = time::add(i, DELTA_MARSEPOCH_JANSIX); + append(ret, time::add(i, DELTA_MARSEPOCH_JANSIX)); + return ret; case => return void; }; - return buf; };