#timezone #local-time #interface #iana #tz #system #libtz

sys libtz-sys

An FFI interface to IANA's timezone library, libtz

6 releases

0.2.2 Jan 28, 2023
0.2.1 Jan 28, 2023
0.1.1 Jan 25, 2023
0.0.0 Jan 25, 2023

#7 in #tz


Used in libtz

Custom license

600KB
8K SLoC

C 7K SLoC // 0.2% comments AWK 1K SLoC // 0.2% comments Korn shell 478 SLoC // 0.1% comments Rust 158 SLoC // 0.0% comments Shell 32 SLoC // 0.1% comments

libtz-sys

Rust FFI interface for IANA's libtz (git repository).

This is a low level library---You will most likely prefer libtz, a more idomatic Rust interface built on top of this.

This provides an equivalent of libc's localtime_r() function (and related functions). The difference is that this library has been compiled such that the getenv("TZ") call uses Rust's std::env::var_os() which protects it from std::env::set_var() races which could otherwise cause segfaults on systems that don't provide multithread safe implementations of getenv() and setenv().

Aside from that it should be a drop in replacement for most libc localtime implementations. It will read the tzdata files that the system has installed to calculate things like leap seconds and daylight saving time.

Links: [Documentation] [Git Repository] [Crates.io]

Usage

Add this to your Cargo.toml:

[dependencies]
libtz-sys = "0.2"

Example

use std::ffi::{CString,CStr};
use std::mem::MaybeUninit;
use libtz_sys::{tzalloc, localtime_rz, mktime_z, tzfree, TimeT, Tm};

let tzname = CString::new("America/New_York").unwrap();
let tz = unsafe { tzalloc(tzname.as_ptr()) };
if tz == std::ptr::null_mut() {
    return Err(std::io::Error::last_os_error());
}
let time: TimeT = 127810800;
let mut tm = MaybeUninit::<Tm>::uninit();
let ret = unsafe { localtime_rz(tz, &time, tm.as_mut_ptr()) };
if ret == std::ptr::null_mut() {
    return Err(std::io::Error::last_os_error());
}
let tm = unsafe { tm.assume_init() };
let zone: &str = unsafe { CStr::from_ptr(tm.tm_zone).to_str().expect("correct utf8") };
assert_eq!((tm.tm_sec, tm.tm_min, tm.tm_hour, tm.tm_mday, tm.tm_mon),
           (0,         0,         3,          19,         0,       ));
assert_eq!((tm.tm_year, tm.tm_wday, tm.tm_yday, tm.tm_isdst, tm.tm_gmtoff, zone),
           (74,         6,          18,         1,           -14400,       "EDT"));

let time_again = unsafe { mktime_z(tz, &tm) }; // Round trip
if time_again == -1 {
    // Didn't work (errno is not reliably set in this case)
} else {
    assert_eq!(time_again, time);
}
unsafe { tzfree(tz) };
# Ok(())

Status

This is young code and designed to be a backend for libtz. It may change rapidly.

License

The Rust code is distributed under the MIT license.

The libtz code is mostly public domain with a couple files using the BSD-3 clause license.

See LICENSE.md for details.

Dependencies