timezone-data 0.2.0

no_std, no-alloc parser for embedded IANA TZif timezone data: transitions, zone types, POSIX TZ rules, leap seconds, and zone metadata.
Documentation
  • Coverage
  • 100%
    52 out of 52 items documented1 out of 4 items with examples
  • Size
  • Source code size: 2.61 MB This is the summed size of all the files inside the crates.io package for this release.
  • Documentation size: 1.04 MB This is the summed size of all files generated by rustdoc for all configured targets
  • Ø build duration
  • this release: 3s Average build duration of successful builds.
  • all releases: 3s Average build duration of successful builds in releases after 2024-10-23.
  • Links
  • KarpelesLab/timezone-data-rs
    0 0 0
  • crates.io
  • Dependencies
  • Versions
  • Owners
  • MagicalTux

timezone-data

Tests crates.io docs.rs License: MIT

A #![no_std], allocation-free Rust crate that exposes IANA timezone data most libraries keep private: transitions, zone types, POSIX TZ rules, leap seconds, and per-zone metadata.

Every zone from the official IANA source is pre-parsed at build time into static Rust objects and embedded in the crate, so there is no dependency on the host system's timezone files, nothing is parsed at runtime, and there are no external crate dependencies at all. A lookup is a binary search over &'static data.

This is a Rust port of the Go package gotz.

Highlights

  • no_std + no alloc. Accessors return slices that point straight at &'static data. Nothing is heap-allocated.
  • Nothing parsed at runtime, no build script. Each zone is materialised as static ZoneType / Transition arrays + a const POSIX rule; load() just binary-searches a static table.
  • Zero dependencies.
  • Complete IANA database embedded (598 zones, plus the zone1970.tab / iso3166.tab metadata tables).

Usage

use timezone_data::load;

let z = load("America/New_York")?;

// Inspect zone types (EST, EDT, ...).
for zt in z.types() {
    println!("{}  offset={}  dst={}", zt.abbrev, zt.offset, zt.is_dst);
}

// Iterate historical transitions.
for t in z.transitions() {
    let zt = z.type_at(t.type_idx);
    println!("{} -> {}", t.when, zt.abbrev);
}

// Look up the active zone at a specific Unix timestamp.
let zt = z.lookup(1_700_000_000);
println!("zone: {} (UTC offset {})", zt.abbrev, zt.offset);

// Get the POSIX TZ rule for future transitions.
if let Some(rule) = z.extend() {
    let (start, end) = rule.transitions_for_year(2025).unwrap();
    println!("DST starts: {start}, ends: {end}");
}

// Country and coordinates metadata.
if let Some(m) = z.meta() {
    if let Some(c) = m.countries().next() {
        println!("country: {} ({})", c.name, c.code);
    }
    println!("location: {}, {}", m.lat, m.lon);
}
# Ok::<(), timezone_data::Error>(())

Times are expressed as i64 Unix seconds — the crate is timezone-library agnostic. If you need a chrono/time value, convert at the boundary.

API overview

Item Description
load(name) -> Result<Zone, Error> Load a zone by IANA name (""/"UTC" → UTC).
load_insensitive(name) Load with case-insensitive fallback.
names() Iterate every IANA zone name.
Zone::types() / type_at(i) Local time types (abbrev, offset, DST flag).
Zone::transitions() Stored transition records.
Zone::leap_seconds() Leap-second records.
Zone::lookup(unix) Zone type in effect at an instant.
Zone::transitions_for_range(start, end) Stored + POSIX-generated transitions in [start, end).
Zone::extend() / extend_raw() Parsed / raw POSIX TZ footer.
Zone::meta() Country + coordinate metadata.
parse_posix_tz(s) Parse a POSIX TZ string directly.

Updating the embedded data

zoneinfo.zip is committed to the repository purely as the data source for the generator; it is not part of the published crate. The generated table (src/generated.rs) and the metadata tables (src/zone1970.tab, src/iso3166.tab) are committed and are what gets shipped.

To refresh from a new IANA release:

  1. Compile the tzdata with zic and repackage it as a STORE (uncompressed) zip — the generator does not implement inflate. The original gotz repository's update.sh / mkzip.go produce a compatible archive.
  2. Replace zoneinfo.zip in this crate's root.
  3. Run cargo run -p xtask to regenerate src/generated.rs and the .tab files, then commit the result.

CI re-runs the generator and fails if the committed output is stale, so a release always ships the current data.

License

MIT. Timezone data is in the public domain (IANA).