///|
/// Reads the file at the NUL-terminated `path`'s raw bytes, or
/// `Bytes::default()` if it could not be read.
#borrow(path)
extern "C" fn read_file_bytes(path : Bytes) -> Bytes = "almanac_read_file"
///|
/// The UTF-8 `TimeZoneKeyName` of the Windows dynamic time zone, or
/// `Bytes::default()` if it could not be read or the host is not Windows.
extern "C" fn windows_zone_key_name_bytes() -> Bytes = "almanac_windows_zone_key_name"
///|
fn host_windows_zone_key() -> String? {
let bytes = windows_zone_key_name_bytes()
if bytes.length() == 0 {
None
} else {
Some(@utf8.decode_lossy(bytes))
}
}
///|
fn read_host_file(path : String) -> Bytes? {
let bytes = read_file_bytes(@utf8.encode(path) + b"\x00")
if bytes.length() == 0 {
None
} else {
Some(bytes)
}
}
///|
/// The host's configured local time zone, or `None` if it could not be
/// determined. Reads live OS state (`$TZ`, `/etc/localtime`, on Windows the
/// zone key name), so it is not a pure function of its arguments; the `$TZ`
/// precedence rules it applies are described on `Local`.
pub fn Local::new() -> Local? {
Local::resolve(
@env.get_env_var("TZ"),
read_host_file,
zoneinfo_dirs=zoneinfo_dirs(@env.get_env_var("ZONEINFO")),
windows_zone_key=host_windows_zone_key(),
)
}
///|
/// The directories searched for TZif files by name: the `ZONEINFO` directory
/// when set and non-empty, then the standard system locations.
fn zoneinfo_dirs(zoneinfo_env : String?) -> Array[String] {
let standard = [
"/usr/share/zoneinfo", "/usr/share/lib/zoneinfo", "/usr/lib/locale/TZ", "/etc/zoneinfo",
]
match zoneinfo_env {
Some(dir) if dir != "" => [dir, ..standard]
_ => standard
}
}
///|
/// Loads the zone `name` (e.g. `"Asia/Tokyo"`) from the first of these that
/// has it: the directory named by `$ZONEINFO`, the system zoneinfo
/// directories (`/usr/share/zoneinfo` and its peers), then the embedded
/// database. This lets a host's tzdata newer than the embedded release take
/// effect. `None` if no source has `name`, or `name` is empty, absolute, or
/// contains `..`. Whether a file name matches regardless of case follows the
/// host file system (e.g. `"asia/tokyo"` is found on macOS); the embedded
/// database is always case-sensitive. Reads live OS state, so it is not a pure function of its
/// arguments; `Location::load` is the embedded-only counterpart.
pub fn Location::load_system(name : String) -> Location? {
Location::load_from_dirs(
name,
zoneinfo_dirs(@env.get_env_var("ZONEINFO")),
read_host_file,
)
}