Skip to content

Commit

Permalink
WC Post Types: Fix timezone offset when sessions happen after DST (#1394
Browse files Browse the repository at this point in the history
)

* WC Post Types: Fix timezone offset when sessions happen after DST

This change updates how the session dates are converted when the site and client timezones are different. Rather than creating a fixed timezone offset on page load, this converts the times into the server timezone for the given date — this way, the offset is correctly applied if a future date is in a different timezone (DST starts or ends).

Fixes #1385

* Fix lint issues
  • Loading branch information
ryelle authored Oct 18, 2024
1 parent c0ab1d5 commit 087161a
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
.wordcamp-panel-session-info .components-datetime__time .components-button,
.wordcamp-panel-session-info .components-datetime__time input[type="number"],
.wordcamp-panel-session-info .components-datetime__time select {
height: 30px;
margin-bottom: 0;
margin-top: 0;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
/**
* External dependencies
*/
import { format } from 'date-fns';
import { TZDate } from '@date-fns/tz';

/**
* WordPress dependencies
*/
// eslint-disable-next-line @wordpress/no-unsafe-wp-apis -- Date settings OK.
import { __experimentalGetSettings, dateI18n } from '@wordpress/date';
import { getSettings } from '@wordpress/date';
import { BaseControl, TimePicker } from '@wordpress/components';
import { sprintf } from '@wordpress/i18n';

const TIMEZONELESS_FORMAT = "yyyy-MM-dd'T'HH:mm:ss";

/**
* Using the site settings, generate the offset in ISO 8601 format (`+00:00`).
*
Expand All @@ -25,7 +32,7 @@ function getTimezoneOffset( { offset = 0 } ) {
}

export default function( { date, label, onChange } ) {
const settings = __experimentalGetSettings();
const settings = getSettings();
const is12HourTime = /a(?!\\)/i.test(
settings.formats.time
.toLowerCase() // Test only the lower case a
Expand All @@ -35,20 +42,44 @@ export default function( { date, label, onChange } ) {
.join( '' ) // Reverse the string and test for "a" not followed by a slash
);

// Remove the timezone info from the date. `TimePicker` uses an instance of moment that does not know about
// the site timezone, so passing it in causes an unexpected offset.
const dateNoTZ = dateI18n( 'Y-m-d\\TH:i:s', date, 'WP' );
// The `TimePicker` component is timezone-agnostic, so `currentTime` should be a
// date-time string without a timezone (but in the server timezone for display).

// First get the server timezone from date settings. This could be a string
// like "America/New_York" or an offset like "-1".
let serverTimezone = settings.timezone.string;
if ( ! serverTimezone ) {
// If it's a offset, convert it to ISO 8601 format.
serverTimezone = getTimezoneOffset( settings.timezone );
}

// Because this date is a timestamp, it's understood to be a UTC value, and
// can be simply created with the correct timezone.
const dateServerTZ = new TZDate( date, serverTimezone );

return (
<BaseControl>
<BaseControl.VisualLabel>{ label }</BaseControl.VisualLabel>
<TimePicker
currentTime={ dateNoTZ }
onChange={ ( dateValue ) => {
// dateValue is a tz-less string, so we need to add the site-timezone offset.
// Otherwise, `dateI18n` tries to use the browser timezone, which might not be the same.
const offset = getTimezoneOffset( settings.timezone );
const value = dateI18n( 'U', dateValue + offset );
currentTime={ format( dateServerTZ, TIMEZONELESS_FORMAT ) }
onChange={ ( newDate ) => {
// Parse the date with the server timezone. This will be an incorrect date, because
// the date is first converted to the client timezone, then the server timezone data
// is added. For example, if the TimePicker reads 9:00 UTC-8 (server timezone), but
// the client timezone is UTC-5, when created, the timestamp for the date will be
// 9:00 UTC-5. Instead, we should create a new date with the server timezone appended,
// so that it will create the correct UTC timestamp.
// This `_date` is only used to get the timezone in the correct format.
const _date = new TZDate( newDate, serverTimezone );

// XXX returns the timezone (ISO-8601 w/ Z), e.g. -08:00.
const timezone = format( _date, 'XXX' );

// Now create a new date with the correct timezone.
const newDateTZ = new Date( newDate + timezone );

// Save value in seconds format for post meta.
const value = format( newDateTZ, 't' );
onChange( value );
} }
is12Hour={ is12HourTime }
Expand Down
6 changes: 4 additions & 2 deletions public_html/wp-content/plugins/wc-post-types/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,19 @@
"url": "https://github.com/WordPress/wordcamp.org/issues?q=label%3A%22%5BComponent%5D+WC-Post-Types%22"
},
"devDependencies": {
"@date-fns/tz": "1.1.2",
"@wordpress/api-fetch": "6.2.0",
"@wordpress/components": "19.7.0",
"@wordpress/compose": "5.3.0",
"@wordpress/data": "6.5.0",
"@wordpress/date": "4.5.0",
"@wordpress/date": "4.58.0",
"@wordpress/edit-post": "6.2.0",
"@wordpress/element": "4.3.0",
"@wordpress/eslint-plugin": "11.1.0",
"@wordpress/i18n": "4.5.0",
"@wordpress/plugins": "4.3.0",
"@wordpress/scripts": "22.3.0"
"@wordpress/scripts": "22.3.0",
"date-fns": "4.1.0"
},
"eslintConfig": {
"extends": "../../../../.eslintrc.js",
Expand Down
47 changes: 47 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2318,6 +2318,11 @@
resolved "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-3.0.0.tgz"
integrity sha512-hBI9tfBtuPIi885ZsZ32IMEU/5nlZH/KOVYJCOh7gyMxaVLGmLedYqFN6Ui1LXkI8JlC8IsuC0rF0btcRZKd5g==

"@date-fns/[email protected]":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@date-fns/tz/-/tz-1.1.2.tgz#c8036db48ae9e7165f40a951942a14070e0c6ec1"
integrity sha512-Xmg2cPmOPQieCLAdf62KtFPU9y7wbQDq1OAzrs/bEQFvhtCPXDiks1CHDE/sTXReRfh/MICVkw/vY6OANHUGiA==

"@discoveryjs/[email protected]":
version "0.5.7"
resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70"
Expand Down Expand Up @@ -4844,6 +4849,16 @@
moment "^2.22.1"
moment-timezone "^0.5.31"

"@wordpress/[email protected]":
version "4.58.0"
resolved "https://registry.yarnpkg.com/@wordpress/date/-/date-4.58.0.tgz#6803e0bde8e8ccb62ebf57554f9543a14cc4433c"
integrity sha512-yFT7DU0H9W0lsDytMaVMmjho08X1LeBMIQMppxdtKB04Ujx58hVh7gtunOsstUQ7pVg23nE2eLaVfx5JOdjzAw==
dependencies:
"@babel/runtime" "^7.16.0"
"@wordpress/deprecated" "^3.58.0"
moment "^2.29.4"
moment-timezone "^0.5.40"

"@wordpress/dependency-extraction-webpack-plugin@^3.4.1":
version "3.4.1"
resolved "https://registry.npmjs.org/@wordpress/dependency-extraction-webpack-plugin/-/dependency-extraction-webpack-plugin-3.4.1.tgz"
Expand All @@ -4868,6 +4883,14 @@
"@babel/runtime" "^7.16.0"
"@wordpress/hooks" "^3.5.0"

"@wordpress/deprecated@^3.58.0":
version "3.58.0"
resolved "https://registry.yarnpkg.com/@wordpress/deprecated/-/deprecated-3.58.0.tgz#c8b9442167bc20aef4888af4a4d081b4553adb4c"
integrity sha512-knweE2lLEUxWRr6A48sHiO0ww5pPybGe2NVIZVq/y7EaYCMdpy6gYA0ZdVqMKZvtxKKqicJfwigcn+hinsTvUQ==
dependencies:
"@babel/runtime" "^7.16.0"
"@wordpress/hooks" "^3.58.0"

"@wordpress/dom-ready@^3.5.0":
version "3.5.0"
resolved "https://registry.npmjs.org/@wordpress/dom-ready/-/dom-ready-3.5.0.tgz"
Expand Down Expand Up @@ -5067,6 +5090,13 @@
dependencies:
"@babel/runtime" "^7.16.0"

"@wordpress/hooks@^3.58.0":
version "3.58.0"
resolved "https://registry.yarnpkg.com/@wordpress/hooks/-/hooks-3.58.0.tgz#68094f7e7e3f8cbc3ab68a0fe9ac2a9b3cfe55d6"
integrity sha512-9LB0ZHnZRQlORttux9t/xbAskF+dk2ujqzPGsVzc92mSKpQP3K2a5Wy74fUnInguB1vLUNHT6nrNdkVom5qX1Q==
dependencies:
"@babel/runtime" "^7.16.0"

"@wordpress/[email protected]", "@wordpress/html-entities@^3.5.0":
version "3.5.0"
resolved "https://registry.npmjs.org/@wordpress/html-entities/-/html-entities-3.5.0.tgz"
Expand Down Expand Up @@ -7424,6 +7454,11 @@ data-urls@^3.0.2:
whatwg-mimetype "^3.0.0"
whatwg-url "^11.0.0"

[email protected]:
version "4.1.0"
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-4.1.0.tgz#64b3d83fff5aa80438f5b1a633c2e83b8a1c2d14"
integrity sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==

debounce@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.2.1.tgz#38881d8f4166a5c5848020c11827b834bcb3e0a5"
Expand Down Expand Up @@ -11935,11 +11970,23 @@ moment-timezone@^0.5.31:
dependencies:
moment ">= 2.9.0"

moment-timezone@^0.5.40:
version "0.5.46"
resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.46.tgz#a21aa6392b3c6b3ed916cd5e95858a28d893704a"
integrity sha512-ZXm9b36esbe7OmdABqIWJuBBiLLwAjrN7CE+7sYdCCx82Nabt1wHDj8TVseS59QIlfFPbOoiBPm6ca9BioG4hw==
dependencies:
moment "^2.29.4"

"moment@>= 2.9.0", moment@>=1.6.0, moment@^2.22.1:
version "2.29.1"
resolved "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz"
integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==

moment@^2.29.4:
version "2.30.1"
resolved "https://registry.yarnpkg.com/moment/-/moment-2.30.1.tgz#f8c91c07b7a786e30c59926df530b4eac96974ae"
integrity sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==

moo@^0.5.0:
version "0.5.1"
resolved "https://registry.npmjs.org/moo/-/moo-0.5.1.tgz"
Expand Down

0 comments on commit 087161a

Please sign in to comment.