Files
Notes/notes-service/vendor/jiff/src/tz/posix.rs
T
2026-08-01 16:11:49 +03:00

102 lines
3.4 KiB
Rust

/*!
Provides a `Display` impl wrapper for POSIX time zones.
This lives here because none of the formatting machinery is available
in `jiff-core`. And while we could still write out a `Display` impl in
`jiff-core`, it doesn't seem worth that duplication.
*/
use jcore::tz::posix;
use crate::fmt;
/// A wrapper around jcore's posix time zone implementation.
///
/// This wrapper provides `Display`, `Debug` and `Format` impls using the
/// formatter in this crate. (jcore does not do formatting.)
pub(crate) struct TimeZoneFormatter<'a>(pub(crate) &'a posix::TimeZone);
impl<'a> core::fmt::Display for TimeZoneFormatter<'a> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
fmt::temporal::DateTimePrinter::new()
.print_posix_time_zone(self.0, fmt::StdFmtWrite(f))
.map_err(|_| core::fmt::Error)
}
}
impl<'a> core::fmt::Debug for TimeZoneFormatter<'a> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
core::fmt::Display::fmt(self, f)
}
}
#[cfg(feature = "defmt")]
impl<'a> defmt::Format for TimeZoneFormatter<'a> {
fn format(&self, f: defmt::Formatter) {
defmt::unwrap!(fmt::temporal::DateTimePrinter::new()
.print_posix_time_zone(self.0, fmt::DefmtWrite(f)))
}
}
// The tests below require parsing which requires alloc.
#[cfg(feature = "alloc")]
#[cfg(test)]
mod tests {
use super::*;
/// Assert that converting the TZ back to a string matches what we got. In
/// the original version of the POSIX TZ parser, we were very meticulous
/// about capturing the exact AST of the time zone. But I've since
/// simplified the data structure considerably such that it is lossy in
/// terms of what was actually parsed (but of course, not lossy in terms of
/// the semantic meaning of the time zone).
///
/// So to account for this, we serialize to a string and then parse it
/// back. We should get what we started with.
#[cfg(feature = "alloc")]
#[test]
fn roundtrips() {
fn assert_roundtrip(tz: &str) {
use alloc::string::{String, ToString};
use jcore::tz::posix;
fn to_string(tz: &posix::TimeZone) -> String {
TimeZoneFormatter(tz).to_string()
}
let tz = posix::TimeZone::parse(tz).unwrap();
let reparsed = posix::TimeZone::parse(to_string(&tz)).unwrap();
assert_eq!(tz, reparsed);
assert_eq!(to_string(&tz), to_string(&reparsed));
}
let cases = [
"WART4WARST,J1/-3,J365/20",
"WART4WARST,J1/-4,J365/21",
"EST5EDT,M3.2.0,M11.1.0",
"XXX-2<+01>-1,0/0,J365/23",
"EST24EDT,J1,J365",
"EST-24EDT,J1,J365",
"EST5EDT,J1,J365/5:12:34",
"EST+5EDT,M3.2.0/2,M11.1.0/2",
"EST+5EDT,M1.1.1,M12.5.2",
"EST5EDT,0/0,J365/25",
"XXX3EDT4,0/0,J365/23",
"XXX3EDT4,0/0,365",
"XXX3EDT4,J1/-167:59:59,J365/167:59:59",
"EST5EDT,J1,J365/5:12:34",
"EST+5EDT,M3.2.0/2,M11.1.0/2",
"EST+5EDT,J60,J365",
"EST+5EDT,59,365",
"EST+5EDT,M1.1.1,M12.5.2",
"EST5EDT,J1,J365/5:12:34",
"EST5EDT,J1/23:59:59,J365/24:00:00",
"EST5EDT,J1/-1,J365/167:00:00",
];
for tz in cases {
assert_roundtrip(tz);
}
}
}