From bdfb04b94be015637532248f3ddc61b88cb996da Mon Sep 17 00:00:00 2001 From: 0xSoftBoi Date: Sun, 5 Apr 2026 21:17:21 -0400 Subject: [PATCH 1/2] fix(offset): accept "ut" / "UT" as a bare UTC timezone abbreviation GNU date -d accepts "ut" and "UT" (Universal Time) as synonyms for UTC. parse_datetime rejected them because the timezone_name_to_offset table contained "utc" and "gmt" but was missing "ut". Add "ut" => "+0" to the lookup table. "gmt" was already present and continues to work unchanged. Add regression tests: - offset-level: timezone_name_without_offset now includes "ut" - lib-level: test_bare_utc_timezone_abbreviations covers all four forms (ut, UT, gmt, GMT) end-to-end Fixes #280 --- src/items/offset.rs | 2 ++ src/lib.rs | 16 ++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/src/items/offset.rs b/src/items/offset.rs index 9dc42f1..71a320b 100644 --- a/src/items/offset.rs +++ b/src/items/offset.rs @@ -281,6 +281,7 @@ fn timezone_name_to_offset(input: &str) -> ModalResult { "w" => Ok("-10"), "v" => Ok("-9"), "utc" => Ok("+0"), + "ut" => Ok("+0"), "u" => Ok("-8"), "t" => Ok("-7"), "sst" => Ok("-11"), @@ -423,6 +424,7 @@ mod tests { fn timezone_name_without_offset() { for (input, expected) in [ ("utc", off(false, 0, 0)), // UTC + ("ut", off(false, 0, 0)), // Universal Time = UTC (issue #280) ("gmt", off(false, 0, 0)), // UTC ("z", off(false, 0, 0)), // UTC ("west", off(false, 1, 0)), // positive offset diff --git a/src/lib.rs b/src/lib.rs index b9ce5fa..b29f639 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -694,6 +694,22 @@ mod tests { } } + /// GNU `date` accepts bare `ut` / `UT` as a synonym for UTC (issue #280). + /// `gmt` and `GMT` already worked; this test covers all four forms. + #[test] + fn test_bare_utc_timezone_abbreviations() { + // All four should parse without error and produce a result in UTC (+00:00). + for abbr in ["ut", "UT", "gmt", "GMT"] { + let result = parse_datetime(abbr) + .unwrap_or_else(|_| panic!("bare timezone '{abbr}' should be accepted")); + let offset_secs = result + .expect_in_range() + .offset() + .seconds(); + assert_eq!(offset_secs, 0, "'{abbr}' should resolve to UTC (+0)"); + } + } + #[test] fn test_weekday_only() { let now = Zoned::now(); From a430ba223a3166929141d19e98e7b8a09c461ab5 Mon Sep 17 00:00:00 2001 From: 0xSoftBoi Date: Mon, 6 Apr 2026 05:26:31 -0400 Subject: [PATCH 2/2] style: run rustfmt on bare UT timezone test --- src/lib.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index b29f639..6dfac00 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -702,10 +702,7 @@ mod tests { for abbr in ["ut", "UT", "gmt", "GMT"] { let result = parse_datetime(abbr) .unwrap_or_else(|_| panic!("bare timezone '{abbr}' should be accepted")); - let offset_secs = result - .expect_in_range() - .offset() - .seconds(); + let offset_secs = result.expect_in_range().offset().seconds(); assert_eq!(offset_secs, 0, "'{abbr}' should resolve to UTC (+0)"); } }