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:
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, []);