hare

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

commit 0f8c679a2a43df23ed3074466df048c173553831
parent 96a3c04ddb1201e7e13cb51d40f3e6bf1e41f79c
Author: Byron Torres <b@torresjrjr.com>
Date:   Sat,  8 Jan 2022 02:05:33 +0000

etch new timezone functions

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

Diffstat:
Mdatetime/calendar.ha | 4++++
Mdatetime/datetime.ha | 14+++++++++-----
Mdatetime/timezone.ha | 5+++--
Mtime/chrono/chronology.ha | 3++-
Mtime/chrono/timezone.ha | 89+++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------
5 files changed, 78 insertions(+), 37 deletions(-)

diff --git a/datetime/calendar.ha b/datetime/calendar.ha @@ -226,6 +226,10 @@ export fn min(dt: *datetime) int = { // Evaluates a [[datetime]]'s second of the minute export fn sec(dt: *datetime) int = { + // TODO: localize datetimes for all functions here. Use localised date + // and time in place of the given datetime's date and time. + const ldt = chrono::localize(to_moment(*dt)); + match (dt.sec) { case void => const hmsn = calc_hmsn(dt.time: time::duration); diff --git a/datetime/datetime.ha b/datetime/datetime.ha @@ -31,7 +31,6 @@ export type datetime = struct { fn init() datetime = datetime { date = 0, time = 0, - zone = chrono::zone{ ... }, loc = chrono::local, era = void, @@ -63,13 +62,12 @@ export fn new( min: int, sec: int, nsec: int, - zoffset: chrono::zoffset, + 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)?, - zone = chrono::zone{ zoffset = zoffset, ... }, loc = if (loc is void) chrono::local else loc: *chrono::timezone, era = void, @@ -95,7 +93,6 @@ export fn clone(dt: datetime) datetime = { return datetime { date = dt.date, time = dt.time, - zone = dt.zone, loc = dt.loc, era = dt.era, @@ -140,7 +137,6 @@ export fn now() datetime = { // TODO: What to do here? How to get the timezone from // /etc/localtime or $TZ? How to determine the system's // timescale? Assuming UTC may be sufficient. - zone = chrono::zone{ ... }, loc = chrono::local, era = void, @@ -257,3 +253,11 @@ export type method = enum uint { // all methods, in order as presented here ALL = YMD | YD | YWD | ISOYWD, }; + +export fn to_moment(dt: datetime) chrono::moment = { + return chrono::moment { + date = dt.date, + time = dt.time, + loc = dt.loc, + }; +}; diff --git a/datetime/timezone.ha b/datetime/timezone.ha @@ -15,7 +15,8 @@ export fn tzdb(name: str) chrono::timezone = { // "CET", "Central European Time" timezone export const TZ_CET: chrono::timezone = chrono::timezone { name = "CET", - scale = &chrono::UTC, + timescale = &chrono::UTC, + daylength = chrono::EARTH_DAY, zones = [ chrono::zone { zoffset = 1 * time::HOUR, @@ -30,5 +31,5 @@ export const TZ_CET: chrono::timezone = chrono::timezone { dst = true, }, ], - trans = [], + transitions = [], }; diff --git a/time/chrono/chronology.ha b/time/chrono/chronology.ha @@ -4,10 +4,11 @@ use time; export type moment = struct { date: epochal, time: time::duration, - zone: zone, loc: locality, }; // An ordinal day (on Earth or otherwise) since the Hare epoch (zeroth day) // 1970-01-01 export type epochal = i64; + +export def EARTH_DAY: time::duration = 86400 * time::SECOND; diff --git a/time/chrono/timezone.ha b/time/chrono/timezone.ha @@ -2,33 +2,45 @@ use time; export type locality = *timezone; -// The zoneinfo of a datetime -export type zoneinfo = struct { - zabbrev: str, // %Z - zoffset: zoffset, // %z -}; +// A timezone; a political region with a ruleset regarding offsets for +// calculating localized civil time +export type timezone = struct { + // The textual identifier ("Europe/Amsterdam") + name: str, -// A simple, constant zone offset -export type zoffset = time::duration; + // The base timescale (chrono::UTC) + timescale: *timescale, -// A timezone; a political region with a ruleset regarding offsets -export type timezone = struct { - name: str, // "Europe/Amsterdam" - scale: *timescale, + // The duration of a day in this timezone (24 * time::HOUR) + // TODO: Make this a function? Some planets may have greater rotational + // acceleration, meaning daylength would change over time. + daylength: time::duration, + + // The possible temporal zones a locality with this timezone can observe + // (CET, CEST, ...) zones: []zone, - trans: []zonetran, + + // The transitions between this timezone's zones + transitions: []transition, }; -// A conditional offset, dependant on the time of year +// A timezone state, with an offset for calculating localized civil time export type zone = struct { - zoffset: zoffset, // 2 * time::HOUR - name: str, // "Central European Summer Time" - abbrev: str, // "CEST" + // The offset from the normal timezone (2 * time::HOUR) + zoffset: time::duration, + + // The full descriptive name ("Central European Summer Time") + name: str, + + // The abbreviated name ("CEST") + abbrev: str, + + // Indicator of Daylight Saving Time dst: bool, // true }; -// A timezone transition -export type zonetran = struct { +// A timezone transition between two zones +export type transition = struct { when: time::instant, zoneindex: int, }; @@ -36,15 +48,31 @@ export type zonetran = struct { // A destructured dual std/dst POSIX timezone. See tzset(3). type tzname = struct { std_name: str, - std_offset: zoffset, + std_offset: time::duration, dst_name: str, - dst_offset: zoffset, + dst_offset: time::duration, dst_start: str, dst_starttime: str, dst_end: str, dst_endtime: str, }; +// Returns a fictitious moment which assumes it's own locality is the normal +// locality. The given timezone is consulted to find the current zone, and its +// offset is applied to the new .date and .time fields. +export fn localize(m: moment) moment = { + const zone = lookupzone(m); + const newtime = m.time + zone.zoffset; + m.time = newtime % m.loc.daylength; + m.date += (newtime / m.loc.daylength); + return m; +}; + +export fn lookupzone(m: moment) zone = { + // TODO: search through m.loc.trans using m.date and m.time + return zone{ ... }; +}; + // The system's local timezone, set during initialisation export const local: *timezone = &TZ_local; @@ -53,7 +81,9 @@ export const local: *timezone = &TZ_local; return; }; const TZ_local: timezone = timezone { - scale = &UTC, + name = "", + timescale = &UTC, + daylength = EARTH_DAY, zones = [ zone { zoffset = 0 * time::SECOND, @@ -62,15 +92,16 @@ const TZ_local: timezone = timezone { dst = false, }, ], - trans = [], - name = "", + transitions = [], }; // The UTC "Zulu" timezone export const UTC_Z: *timezone = &TZ_UTC; const TZ_UTC: timezone = timezone { - scale = &UTC, + name = "Etc/UTC", + timescale = &UTC, + daylength = EARTH_DAY, zones = [ zone { zoffset = 0 * time::SECOND, @@ -79,15 +110,16 @@ const TZ_UTC: timezone = timezone { dst = false, }, ], - trans = [], - name = "Etc/UTC", + transitions = [], }; // The TAI "Zulu" timezone export const TAI_Z: *timezone = &TZ_TAI; const TZ_TAI: timezone = timezone { - scale = &TAI, + name = "", + timescale = &TAI, + daylength = EARTH_DAY, zones = [ zone { zoffset = 0 * time::SECOND, @@ -96,6 +128,5 @@ const TZ_TAI: timezone = timezone { dst = false, }, ], - trans = [], - name = "", + transitions = [], };