Skip to content

infinityabundance/strftime-rs

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

strftime-rs

A Rust port of upstream tzcode strftime.c formatting semantics, provided as the strftime library crate. It formats an explicit broken-down time (Tm) by a strftime format string, reproducing what tzcode's strftime writes under the C / C.UTF-8 locale. It is the formatting layer over localtime-rs in the Rust tzdb runtime toolchain.

let tm = strftime::Tm { tm_year: 101, tm_mon: 8, tm_mday: 9, tm_hour: 1,
    tm_min: 46, tm_sec: 40, tm_wday: 0, tm_yday: 251, tm_isdst: 0,
    tm_gmtoff: Some(0), tm_zone: Some("UTC".into()) };
assert_eq!(strftime::format_tm("%Y-%m-%d %H:%M:%S %Z", &tm).unwrap(),
           "2001-09-09 01:46:40 UTC");

Claim boundary

strftime-rs does not replace libc strftime, does not implement locale-complete date formatting, and does not define civil-time truth. It ports the observable formatting semantics of upstream tzcode strftime.c under pinned C / C.UTF-8 locale settings and verifies output against the compiled upstream C oracle for admitted tm rows and format strings. It is not a general date-formatting framework, a chrono/jiff competitor, a locale/ICU layer, or a human-date library.

API

pub struct Tm { tm_sec, tm_min, tm_hour, tm_mday, tm_mon, tm_year,
                tm_wday, tm_yday, tm_isdst: i32,
                tm_gmtoff: Option<i32>, tm_zone: Option<String> }

// everyday: no length limit; returns the formatted string.
pub fn format_tm(format: &str, tm: &Tm) -> Result<String, Error>;

// C-like strftime(s, maxsize, …): maxsize includes the NUL; Err(Range) on overflow.
pub fn strftime_limited(format: &str, tm: &Tm, maxsize: usize) -> (Result<usize, Error>, String);

tm_gmtoff / tm_zone are explicit because %z / %Z need them. Fields are used verbatim (no normalization), exactly as strftime.c reads them.

Coverage

Every directive strftime.c handles: %A %a %B %b %h %C %c %D %d %e %F %H %I %j %k %l %M %m %n %p %R %r %S %s %T %t %U %u %V %G %g %v %W %w %X %x %y %Y %Z %z %+ %%, the E/O modifiers (ignored under C), and the exact unknown-conversion / trailing-% passthrough (%q%q, %K%K). First seal: C / C.UTF-8 locale only.

Oracle & evidence

The oracle is a C harness linking upstream strftime.c, fed explicit struct tm rows (decoupled from runtime conversion), printing retlen|output.

  • Sweep: per-pair 1105 / 0 + full-stream byte-identical. 17 tm rows (UTC, pre-1900 / year-1 / year-10000, 2038, leap-second tm_sec=60, isdst-unknown, ±/non-hour gmtoff, empty/long/--leading zone, week-year boundaries, Feb 29) × 65 formats (every directive + composites + E/O + unknown + edges). Receipt: reports/strftime-oracle/.
  • Integration (localtime-rs → strftime-rs): 448 / 0 vs the combined upstream localtime.c+strftime.c oracle (7 zones × 8 timestamps × 8 formats) — the end-to-end timestamp → local time → formatted string path.
  • Kani: the weekday/month name-table index is proven in bounds.
  • Fuzz: cargo +nightly fuzz run fmt over format strings × arbitrary tm fields × buffer sizes — 0 crashes.

Build & test

cargo test
cargo clippy --all-targets -- -D warnings
cargo kani --harness name_index_in_bounds
python3 lab/oracle/sweep.py          # needs the compiled strftime.c harness

License

BSD-3-Clause, retaining the upstream Regents / tz contributors copyright (strftime.c is BSD-licensed). An independent reimplementation.

About

Rust port of upstream tzcode strftime.c formatting semantics (C/C.UTF-8 locale) — formats an explicit tm, verified field-for-field against a compiled strftime.c oracle. Not a libc/locale formatter.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors