A faithful, memory-safe Rust port of upstream leapseconds.awk from the
IANA time zone database — the tool that
turns the NIST/IERS leap-seconds.list file into the zic leapseconds source
file (the leap-second table that zic -L compiles into right/ zones).
leapseconds-rs leap-seconds.list # zic `leapseconds` source on stdout
leapseconds-rs --expires-line in.list # emit a live (uncommented) Expires line
leapseconds-rs < leap-seconds.list # read from stdin
leapseconds.awk is a transformer, so correctness here means byte-for-byte
identical output to the real awk oracle. leapseconds-rs reproduces the
upstream tzdb-2026b leapseconds file exactly, and reproduces the 2026b script's
output on every IANA release back to 2016g (see Evidence).
leapseconds-rs does not define leap-second policy or claim clock truth. It
ports upstream leapseconds.awk behaviour into Rust for pinned tzdb/IERS-style
inputs and verifies the generated leap-second source against the upstream AWK
oracle. Leap-second policy is set by the IERS; the canonical data is
leap-seconds.list. This is a source-generation / QA layer of the Rust tzdb
toolchain, beside zic-rs,
ziguard-rs,
zishrink-rs,
checktab-rs,
checklinks-rs, and
checknow-rs.
Given a NIST/IERS-format leap-seconds.list (NTP-epoch timestamps + running
TAI−UTC offsets) leapseconds-rs emits the zic leapseconds source:
- the fixed public-domain header comment block;
- one
Leap YEAR MON DAY 23:59:60 + Sline per added leap second (and the23:59:59 -form for the unlikely negative leap), the date computed by the awk's exact Gregorian-calendar integer arithmetic (sstamp_to_ymdhMs); - an
Expiresline — commented out by default (EXPIRES_LINE=0, so pre-2020azicdoes not reject the file) or live under--expires-line; - the
#updated/#expiresPOSIX-timestamp comments and the trailing human-readable update/expiry lines.
A port, not a reimagining. Each step mirrors a line of the pinned tzdb-2026b
leapseconds.awk (sha256 76c289f5…), cited in src/lib.rs comments. The
header block is embedded byte-for-byte from the oracle output (it contains
literal tabs). No regex and zero runtime dependencies;
#![forbid(unsafe_code)]; overflow-checks on in release.
- 2026b oracle: byte-identical to the shipped
leapseconds(sha256d6c8c033…) in bothEXPIRES_LINEmodes —tests/oracle.rs. - Constructed fixtures: negative leap, no-expires/no-updated, CRLF,
live-
Expires, comment-only, single-data — each matched against the realawkoracle (tests/cases.rs). - All-release sweep: every signed IANA
tzdb-*.tar.lzshippingleapseconds.awk+leap-seconds.list(48 releases, 2016g…2026b, all GOODSIG) — feed that release'sleap-seconds.listto the pinned-2026b awk and to leapseconds-rs: 48/48 byte-identical (0 port bugs). 3 releases reproduce their own script exactly; the other 45 differ only in upstream header/comment text evolution (identical leap-data lines). Receipt:reports/release-all/. - Kani: the month index into the abbreviation table is proven in-bounds for
any timestamp (
month_index_maps_into_abbr_range) — no OOB panic. - Fuzz:
cargo +nightly fuzz run generateover malformed leap rows — 894k+ executions, 0 crashes. Receipt:reports/fuzz/.
cargo build --release
cargo test # oracle + fixtures (oracle test skips if lab/ absent)
cargo clippy --all-targets -- -D warnings
cargo kani --harness month_index_maps_into_abbr_range
Apache-2.0. The upstream leapseconds.awk and leap-seconds.list are public
domain (IANA / NIST / IERS); this Rust port is an independent reimplementation.