Skip to content

fix(timezone): read full posix rules in TZ="..." - #342

Open
jayhemnani9910 wants to merge 1 commit into
uutils:mainfrom
jayhemnani9910:tz-rule-full-posix
Open

jayhemnani9910 wants to merge 1 commit into
uutils:mainfrom
jayhemnani9910:tz-rule-full-posix

Conversation

@jayhemnani9910

Copy link
Copy Markdown
Contributor

TZ="..." only parses the STDOFFSET part of a posix rule (the TODO on posix). Anything more goes wrong in one of two ways:

  • a rule with a DST part makes the whole input invalid: TZ="CET-1CEST,M3.5.0,M10.5.0/3" 2026-07-01 12:00, TZ="EST5EDT" 2026-07-01 12:00
  • a quoted name (<+03>-3, the form tzdata uses for zones with no abbreviation, e.g. the footer of Europe/Istanbul) doesn't match posix, falls through to the IANA lookup and silently becomes UTC
$ gnudate -u -d 'TZ="<+03>-3" 2026-07-01 12:00'      # GNU 9.7
Wed Jul  1 09:00:00 UTC 2026
$ date -u -d 'TZ="<+03>-3" 2026-07-01 12:00'         # uutils 0.10.0
Wed Jul  1 12:00:00 UTC 2026

The same rules work when they come from the TZ env var, since jiff reads those.

Now posix only takes a rule that ends after STDOFFSET, so the simple cases (and their hour/minute clamping) stay as they are. Anything else that isn't an IANA name goes to jiff::tz::TimeZone::posix. A rule that starts like a posix rule but is broken further on (EST5EDT,, EST5EDT,M3.2.0) is still an error, as it is now, instead of falling back to UTC. A DST name with no rule (EST5EDT, XYZ+5ABC) gets the US rules (M3.2.0,M11.1.0), which is what glibc does, so it works without a zoneinfo file of that name. On Ubuntu 26.04 the tzdata package doesn't have EST5EDT anymore, and uutils date -d 'TZ="EST5EDT" 2026-07-01 12:00' says invalid date there.

Testing:

  • New cases in tz_rule for DST rules, EST5EDT and quoted names, checking the offset in July and January. They fail without the change. Three broken rules are added to the invalid list.
  • cargo test: all pass, same counts as main. cargo clippy --all-targets and cargo fmt --check clean.
  • Compared TZ="RULE" 2026-07-01 12:00 and 2026-01-01 12:00 with GNU date 9.7 for about 30 rules (DST rules with M, J and day-number dates, quoted names, too-short names, unknown names, hour > 24): all the same now. What's left I didn't touch: glibc accepts broken rules (EST5EDT,, junk after a full rule) that stay an error here, and on the US switch day its default rules give a different hour for non-US offsets (<+03>-3<+04> on 2026-03-08).
  • Built uutils date (coreutils 865e575) against this branch with a [patch.crates-io] entry and ran date -u -d '<rule> 2026-07-01 12:00': <+03>-3 gives 09:00 (12:00 with 0.17.0), and CET-1CEST,M3.5.0,M10.5.0/3 and EST5EDT give 10:00 and 16:00 instead of "invalid date". All three now match GNU. UTC+5 and Europe/Paris are unchanged.

Only the STDOFFSET part of a posix rule was parsed. A rule with a DST
part (TZ="CET-1CEST,M3.5.0,M10.5.0/3", TZ="EST5EDT") made the whole
input invalid, and a quoted name (TZ="<+03>-3") fell through to the IANA
lookup and silently became UTC.

Keep the STDOFFSET parser for rules that end there, and hand anything
else that is not an IANA name to jiff's posix parser. A DST name without
a rule gets the US rules, as glibc does. A rule that starts like a posix
rule but is broken further on stays an error.
Copilot AI balanced review requested due to automatic review settings October 20, 2026 05:56

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing. Review the Copilot code review billing settings.

@codspeed

codspeed Bot commented Oct 20, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will degrade performance by 3.32%

⚠️ 14 benchmarks spent significant time in system calls

System calls cannot be consistently instrumented, so they are not included in the measure, which understates the real cost. Please switch to the Walltime instrument to accurately measure system calls.

Measurement and system calls

⚠️ Different runtime environments detected

Some benchmarks with significant performance changes were compared across different runtime environments,
which may affect the accuracy of the results.

Open the report in CodSpeed to investigate

❌ 1 regressed benchmark
✅ 20 untouched benchmarks

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Benchmark BASE HEAD Efficiency
❌ ⚠️ parse_epoch_timestamp 11.4 µs 11.7 µs -3.32%

Tip

Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.


Comparing jayhemnani9910:tz-rule-full-posix (6af316c) with main (d5c7380)

Open in CodSpeed

@codecov

codecov Bot commented Oct 20, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 97.75%. Comparing base (d5c7380) to head (6af316c).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #342      +/-   ##
==========================================
+ Coverage   97.73%   97.75%   +0.01%     
==========================================
  Files          21       21              
  Lines        4421     4454      +33     
  Branches      139      139              
==========================================
+ Hits         4321     4354      +33     
  Misses         99       99              
  Partials        1        1              
Flag Coverage Δ
macos_latest 97.75% <100.00%> (+0.01%) ⬆️
ubuntu_latest 97.75% <100.00%> (+0.01%) ⬆️
windows_latest 12.34% <15.78%> (+0.02%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@jayhemnani9910

Copy link
Copy Markdown
Contributor Author

The flagged benchmark is parse_epoch_timestamp (@1613371067). That input fails the TZ=" literal at the start of timezone::parse, before any code this PR changes, so the epoch path is the same. CodSpeed also notes different runtime environments for the comparison. Locally with criterion, main against its own saved baseline moves between -5.4% and +3.5% over runs, and this branch lands at +1.4% to +2.2%, inside that range.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants