Skip to content

[pickers] Fix duplicate hour label in MultiSectionDigitalClock on DST day#22110

Draft
LukasTy wants to merge 2 commits intomui:masterfrom
LukasTy:claude/relaxed-lederberg
Draft

[pickers] Fix duplicate hour label in MultiSectionDigitalClock on DST day#22110
LukasTy wants to merge 2 commits intomui:masterfrom
LukasTy:claude/relaxed-lederberg

Conversation

@LukasTy
Copy link
Copy Markdown
Member

@LukasTy LukasTy commented Apr 16, 2026

Summary

Fixes #22084.

On a DST spring-forward day in timezones like America/Chicago or America/Los_Angeles, the MultiSectionDigitalClock hour column rendered "03" twice and omitted "02". The picker also emitted a duplicate React key warning.

Root cause: labels were produced via adapter.format(adapter.setHours(now, hour), 'hours12h'). On the DST day, setHours(now, 2) returns a date whose local hour is 3 (because 2 AM does not exist locally and the adapter rolls forward), so the label for hour=2 came out as "03" — same label as hour=3.

Fix: use a fixed DST-free reference day (January 15 of the same year, in the same timezone as now) as the base for adapter.setHours when generating labels. The existing adapter.format + formatNumber pipeline is preserved, so locale-specific formats (custom hours12h / hours24h via LocalizationProvider, unpadded tokens like 'h', non-ASCII numeric systems such as Arabic) keep working.

Before (Mar 8 2026, Chicago picker timezone, LA system timezone):

12, 01, 03 (disabled), 03 (selected), 04, 05, ..., 11

After:

12, 01, 02 (disabled), 03 (selected), 04, 05, ..., 11

Note on #21669

This PR does not address #21669 (the "cannot select 4 AM" report). While the duplicate-label bug fixed here made the picker look broken around the DST transition, the author has indicated they've found a separate root cause for #21669 and will address it in a follow-up.

Test plan

  • Added timezone.MultiSectionDigitalClock.test.tsx with:
    • A describeAdapters pair asserting 12- and 24-hour columns have unique labels on the DST day (runs across dayjs / date-fns / luxon / moment)
    • A scenario using clockConfig: new Date('2026-03-08T15:00:00.000Z') that puts the adapter's now on the DST day (the default June 15 clock in describeAdapters wouldn't reach the bug). Covers both the unique-label assertion and clicking "4 hours" to set the value to 4 AM
  • Both new assertions fail without the fix (expected 11 to equal 12 for unique labels; "Found multiple elements with the role 'option' and name ..." when clicking a DST-affected hour) and pass with it
  • Full x-date-pickers suite: 3248 pass, 0 fail
  • Full x-date-pickers-pro suite: 986 pass, 0 fail
  • pnpm --filter "@mui/x-date-pickers*" run typescript clean
  • pnpm prettier clean

…ST day

On the DST spring-forward day, `adapter.setHours(now, 2)` (Chicago / LA
timezones, with certain adapters) returns a date whose local hour is 3
because 2 AM does not exist. That made the hours column render `"03"`
twice and drop `"02"`, which with the v8 skipped-hour disable check
presented as a confusing picker with hours like `04` appearing
unselectable.

Compute the label directly from the loop index instead of formatting a
DST-affected date. `TimeClock`'s `getHourNumbers` already uses this
approach.

Fixes mui#21669
Fixes mui#22084

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@LukasTy LukasTy added type: regression A bug, but worse, it used to behave as expected. scope: pickers Changes related to the date/time pickers. feature: time-zone Issues about time zone management. labels Apr 16, 2026
@LukasTy LukasTy self-assigned this Apr 16, 2026
@code-infra-dashboard
Copy link
Copy Markdown

code-infra-dashboard Bot commented Apr 16, 2026

Bundle size

Bundle Parsed size Gzip size
@mui/x-data-grid 0B(0.00%) 0B(0.00%)
@mui/x-data-grid-pro 0B(0.00%) 0B(0.00%)
@mui/x-data-grid-premium 0B(0.00%) 0B(0.00%)
@mui/x-charts 0B(0.00%) 0B(0.00%)
@mui/x-charts-pro 0B(0.00%) 0B(0.00%)
@mui/x-charts-premium 0B(0.00%) 0B(0.00%)
@mui/x-date-pickers 🔺+46B(+0.02%) 🔺+23B(+0.04%)
@mui/x-date-pickers-pro 🔺+46B(+0.01%) 🔺+25B(+0.03%)
@mui/x-tree-view 0B(0.00%) 0B(0.00%)
@mui/x-tree-view-pro 0B(0.00%) 0B(0.00%)

Details of bundle changes

Deploy preview

https://deploy-preview-22110--material-ui-x.netlify.app/


Check out the code infra dashboard for more information about this PR.

Switch the DST-safe fix from hardcoded digit formatting to using a
DST-free reference day (January 15) as the base for `adapter.setHours`.
This keeps the original `adapter.format` + `formatNumber` pipeline so:
- Custom `formats.hours12h` / `formats.hours24h` from
  `LocalizationProvider` (e.g. `'h'` without padding) are respected.
- Locales that render digits differently through the adapter's format
  function keep working.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@LukasTy LukasTy removed the type: regression A bug, but worse, it used to behave as expected. label Apr 16, 2026
@LukasTy LukasTy changed the title [pickers] Fix duplicate hour label in MultiSectionDigitalClock on DST day [pickers] Fix duplicate hour label in MultiSectionDigitalClock on DST day Apr 16, 2026
@LukasTy LukasTy added the type: bug It doesn't behave as expected. label Apr 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature: time-zone Issues about time zone management. scope: pickers Changes related to the date/time pickers. type: bug It doesn't behave as expected.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[pickers] Duplicate 03:00 AM entry in TimePicker during DST transition (March 8)

1 participant