Skip to content

Fix POSIX TZ week-of-month calculation near DST transitions - #760

Closed
abhinav-phi wants to merge 2 commits into
boa-dev:mainfrom
abhinav-phi:fix-posix-dst-week
Closed

abhinav-phi wants to merge 2 commits into
boa-dev:mainfrom
abhinav-phi:fix-posix-dst-week

Conversation

@abhinav-phi

Copy link
Copy Markdown

Fixes #759

MwdForTime::from_seconds computed week_of_month as day_of_month / 7 + 1,
so day 7 (and day 14, 21, 28) landed in the following week block. When the
queried date and the POSIX transition date fall on opposite sides of that
boundary, the weekday comparison in cmp_seconds_to_transitions orders them
wrongly and the DST offset is picked a day early.

Concretely, for America/New_York in 2026, March 1 is a Sunday. March 7
(Saturday) and March 8 (Sunday, the DST start) were both normalized to week 3,
so March 7 compared as after the transition:

let pdt = PlainDateTime::try_new_iso(2026, 3, 7, 12, 0, 0, 0, 0, 0).unwrap();
// before: 2026-03-07T12:00:00-04:00[America/New_York]
// after:  2026-03-07T12:00:00-05:00[America/New_York]

Use (day_of_month - 1) / 7 + 1 so the seven day blocks start on day 1, which
is what normalize_to_week_number assumes. One line changes.

Tests:

  • New new_york_standard_time_before_dst_start in
    crates/temporal/src/builtins/compiled/plain_date_time.rs (fails before the
    change with -04:00, passes after).
  • cargo test -p temporal: 191 passed, 55 doc tests passed.
  • cargo test -p timezone_provider --features tzif: 24 passed.

MwdForTime::from_seconds divided the day of month by 7 before subtracting one, so day 7 and day 8 both fell in the second week. Comparing a date in that range with a transition date inverted the order for some months, and the offset resolution then picked the daylight saving offset a day early. Use (day - 1) / 7 so the weekly blocks start on day 1.

@Manishearth Manishearth left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This looks about right.

#[test]
fn new_york_standard_time_before_dst_start() {
use crate::{options::Disambiguation, tzdb::CompiledTzdbProvider, PlainDateTime, TimeZone};
let provider = &CompiledTzdbProvider::default();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Please use the test_all_providers macro

If necessary, move it into a test_utils.rs file.

@Manishearth

Copy link
Copy Markdown
Contributor

Fixes #759

This doesn't fix the Europe/London issue

@Manishearth

Copy link
Copy Markdown
Contributor

Made #761

@jedel1043

Copy link
Copy Markdown
Member

Superseeded by #761

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.

PlainDateTime -> ZonedDateTime returns the wrong value in the week before certain DST transitions

3 participants