hare

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

commit b0499b70e5e9fdfed10b3b17cc7c00acea020473
parent 6d3ed8e222d44573dcd94ab2c19f577a4353dee8
Author: Byron Torres <b@torresjrjr.com>
Date:   Thu, 22 Feb 2024 23:43:58 +0000

time::chrono: improve LOCAL, tz()

Make [[LOCAL]] default to [[UTC]] proper.

Accept the POSIX $TZ environment variable form with a ':' prefix.

Allow [[tz]] to accept full filepaths as in POSIX.

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

Diffstat:
Mhare/module/format.ha | 2+-
Mtime/chrono/timezone.ha | 78+++++++++++++++++++++---------------------------------------------------------
Mtime/chrono/tzdb.ha | 20+++++++++++++-------
3 files changed, 35 insertions(+), 65 deletions(-)

diff --git a/hare/module/format.ha b/hare/module/format.ha @@ -35,7 +35,7 @@ export fn format_srcset(out: io::handle, srcs: *srcset) (size | io::error) = { n += fmt::fprint(out, "relevant tags: ")?; n += format_tags(out, srcs.seentags)?; n += fmt::fprintln(out)?; - const dt = date::from_instant(time::chrono::LOCAL, srcs.mtime); + const dt = date::from_instant(chrono::LOCAL, srcs.mtime); n += date::format(out, "last change to source list: %F %T\n", &dt)?; n += fmt::fprintln(out, "hare sources:")?; for (let i = 0z; i < len(srcs.ha); i += 1) { diff --git a/time/chrono/timezone.ha b/time/chrono/timezone.ha @@ -181,77 +181,41 @@ export fn fixedzone(ts: *timescale, daylen: time::duration, z: zone) timezone = }; }; -// The system's [[locality]]; the system's local [[timezone]]. +// The local [[locality]]; the system or environment configured [[timezone]]. // // This is set during a program's initialisation, where the TZ environment -// variable is tried, otherwise the /etc/localtime file is tried, otherwise a -// default is used. -// -// The default timezone is equivalent to that of [[UTC]], with "Local" being the -// name of both the timezone and its single zero-offset zone. -export const LOCAL: locality = &TZ_LOCAL; - -def TZ_LOCAL_NAME: str = "Local"; - -let TZ_LOCAL: timezone = timezone { - name = TZ_LOCAL_NAME, - timescale = &utc, - daylength = EARTH_DAY, - zones = [ - zone { - zoff = 0 * time::SECOND, - name = TZ_LOCAL_NAME, - abbr = "", - dst = false, - }, - ], - transitions = [], - posix_extend = "", -}; +// variable is tried, otherwise the /etc/localtime file is tried, otherwise it +// defaults to [[UTC]]. +export const LOCAL: locality = &TZ_UTC; @init fn init_tz_local() void = { - match (os::getenv("TZ")) { - case let timezone: str => - match (tz(timezone)) { - case let loc: locality => - TZ_LOCAL = *loc; - case => - return; + let path = match (os::getenv("TZ")) { + case let path: str => + // remove POSIX prefix ':' + yield if (strings::hasprefix(path, ':')) { + yield strings::sub(path, 1, strings::end); + } else { + yield path; }; case void => - const filepath = match (os::readlink(LOCALTIME_PATH)) { - case let fp: str => - yield fp; - case => - yield LOCALTIME_PATH; - }; - - const file = match (os::open(filepath)) { - case let f: io::file => - yield f; + yield match (os::realpath(LOCALTIME_PATH)) { + case let path: str => + yield path; case => return; }; - defer io::close(file)!; - - if (strings::hasprefix(filepath, ZONEINFO_PREFIX)) { - TZ_LOCAL.name = strings::trimprefix( - filepath, ZONEINFO_PREFIX, - ); - }; + }; - static let buf: [os::BUFSZ]u8 = [0...]; - const file = bufio::init(file, buf, []); - load_tzif(&file, &TZ_LOCAL): void; + match (tz(path)) { + case => void; + case let loc: locality => + LOCAL = loc; }; }; @fini fn free_tz_local() void = { - free(TZ_LOCAL.transitions); - switch(TZ_LOCAL.name) { - case TZ_LOCAL_NAME => void; - case => - free(TZ_LOCAL.zones); + if (LOCAL != UTC) { + timezone_free(LOCAL); }; }; diff --git a/time/chrono/tzdb.ha b/time/chrono/tzdb.ha @@ -19,16 +19,22 @@ export type tzdberror = !(invalidtzif | fs::error | io::error); export type invalidtzif = !void; // Finds, loads, and allocates a [[timezone]] from the system's Timezone -// database, normally located at /usr/share/zoneinfo, and returns it as a -// [[locality]]. Each call returns a new instance. The caller must free the -// return value. +// database (TZDB), and returns it as a [[locality]]. Each call returns a new +// instance. The caller must free the return value; see [[timezone_free]]. // -// All localities provided default to the [[utc]] [[timescale]] and +// The system TZDB is normally located at [[ZONEINFO_PREFIX]]. The timezone +// filepath is resolved by appending the name argument to this prefix path. +// If [name] is a full filepath (begins with '/'), it is used directly instead. +// +// All localities returned default to the [[utc]] [[timescale]] and // [[EARTH_DAY]] day-length. export fn tz(name: str) (locality | tzdberror) = { - const filepath = path::init(ZONEINFO_PREFIX, name)!; - const fpath = path::string(&filepath); - const file = os::open(fpath)?; + const filepath = + if (!strings::hasprefix(name, ZONEINFO_PREFIX)) + path::init(ZONEINFO_PREFIX, name)! + else + path::init(name)!; + const file = os::open(path::string(&filepath))?; static let buf: [os::BUFSZ]u8 = [0...]; const bufstrm = bufio::init(file, buf, []);