-
Notifications
You must be signed in to change notification settings - Fork 4.6k
Components: Normalize displayed dates to UTC time for DateTimePicker #73444
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message. To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
| > | ||
| { calendar[ 0 ][ 0 ].map( ( day ) => ( | ||
| <DayOfWeek key={ day.toString() }> | ||
| { dateI18n( 'D', day, -day.getTimezoneOffset() ) } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can also be achieved by passing true as the third argument of dateI18n, but it's described as being "effectively deprecated". It's unclear but I don't get the impression that "effectively deprecated" extends to gmtdateI18n itself.
gutenberg/packages/date/src/index.ts
Lines 493 to 497 in 69251a1
| * @param timezone Timezone to output result in or a | |
| * UTC offset. Defaults to timezone from | |
| * site. Notice: `boolean` is effectively | |
| * deprecated, but still supported for | |
| * backward compatibility reasons. |
tyxla
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't seem to work well with the default UTC+0 timezone:
Screen.Recording.2025-11-20.at.15.29.54.mov
See how the date in the field above differs from the selected date in the calendar.
Good catch. I think there was a few factors here with how the original bug report masked further potential issues because the local time (GMT) had no timezone offset, but problems started to arise when there was an offset. Additionally, the previous timezone mocking approach didn't appear entirely sufficient to emulate a local timezone, since it only affected calls to |
| if ( typeof input === 'string' ) { | ||
| return new Date( input ); | ||
| // Check if the string ends with a timezone indicator per ISO-8601. | ||
| const hasTimezone = /Z|[+-]\d{2}(:?\d{2})?$/.test( input ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's some similar patterns and usage in the date library, but (besides not being publicly exported) they're focused around checking just the timezone portion of the string and not an entire timezoneless string.
gutenberg/packages/date/src/index.ts
Lines 22 to 24 in 09eeecb
| // This regular expression tests positive for UTC offsets as described in ISO 8601. | |
| // See: https://en.wikipedia.org/wiki/ISO_8601#Time_offsets_from_UTC | |
| const VALID_UTC_OFFSET = /^[+-][0-1][0-9](:?[0-9][0-9])?$/; |
|
Size Change: +268 B (+0.01%) Total Size: 2.54 MB
ℹ️ View Unchanged
|
|
Flaky tests detected in c05bed0. 🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/19543582283
|
Do we still need a test without an offset (UTC+0), you know, just in case? It might be testing against the timezone mock library at first glance, but it would be ensuring we're catching a real bug here. |
tyxla
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is testing well now, and I played with a bunch of DST scenarios and timezones. Nice. Just a few more questions and nitpicks 😉
| datetimeAbbreviated: 'M j, Y g: i a', | ||
| }, | ||
| timezone: { offset: '0', offsetFormatted: '0', string: '', abbr: '' }, | ||
| timezone: { offset: 0, offsetFormatted: '0', string: '', abbr: '' }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can the change in type bite us in any way?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change is more accurate to the true behavior that happens in a real WordPress environment.
You can verify this on trunk that the number reported is numeric:
wp.date.getSettings().timezone.offset
// 0
These defaults are rarely used, as in WordPress they're overridden as part of the inline script for wp-date (source).
As far as usage, it could have two effects, both of which could be perceived as a positive:
- We're usually converting this to a number anyways (example, example), where using a number instead of a string should have the same result. This is one of those cases where we probably don't even need to be doing this conversion if we could rely strictly on TypeScript types to enforce it as numeric.
- In cases where we're not, we're treating it as already numeric (example), where this change could be fixing some potential bugs
matches original bug behavior, adds additional assurances in how we're using UTC as a baseline for formatting and normalizing dates
More accurate to the user's experience
Yeah, I think it makes sense to include a case, since there could be some potential edge cases where the local browser time is already the same time as the timezone we're normalizing to (UTC). It's also pretty easy to add in how we're using |
tyxla
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @aduth, let's get it 🚢!
What?
Fixes #67480
Fixes an issue where differences between local browser and server timezones could cause incorrect dates to appear selected when choosing a date in the date picker.
Separately, fixes a minor TypeScript typings issue with the
offsetvalue in timezone settings, which are in-fact numeric (source).Why?
Without these changes, there's a potential that posts could become published at a different time than expected.
How?
Fixes the issue by normalizing displayed values to UTC.
DateTimePickervalues are without timezone (e.g.2025-11-19T00:00:00. Previously, these would be converted to browser local time before display, meaning that the options and numbers shown on the calendar may not actually align to the value saved for the post.Testing Instructions
Verify that picking a date around DST boundary selects the expected date:
Repeat these steps in the following circumstance:
Bonus points: Verify that the included regression tests fail on
trunk, as a demonstration of the buggy behavior being effectively tested:git checkout trunkgit checkout fix/date-time-timezone-dst -- packages/components/src/date-time/date-time/test/index.tsxnpm run test:unit packages/components/src/date-time/date-time/test/index.tsxScreenshots or screencast
The following screenshots show the result after clicking "1" in the scenario described above with GMT local time + EST server time.
Observe: