diff --git a/package.json b/package.json index aa251f7ce3c..5014052fb3c 100644 --- a/package.json +++ b/package.json @@ -86,6 +86,7 @@ "react-dom": "19.2.6", "react-helmet": "6.1.0", "react-lazyload": "3.2.1", + "temporal-polyfill": "0.3.0", "undici": "8.3.0", "uuid": "13.0.1", "winston": "patch:winston@3.8.2#./patches/winston-file-descriptor.patch" diff --git a/src/app/legacy/psammead/psammead-timestamp-container/src/utilities/index.js b/src/app/legacy/psammead/psammead-timestamp-container/src/utilities/index.js index a0120c705a2..95c2cc49b5f 100644 --- a/src/app/legacy/psammead/psammead-timestamp-container/src/utilities/index.js +++ b/src/app/legacy/psammead/psammead-timestamp-container/src/utilities/index.js @@ -1,5 +1,28 @@ +import 'temporal-polyfill/global'; import moment from 'moment-timezone'; +const createDateAdapter = () => ({ + // Temporary seam for gradual Temporal adoption in follow-up PRs. + createLocalisedMoment: ({ locale, timestamp }) => + moment(timestamp).locale(locale), + createMomentInTimezone: ({ locale, timestamp, timezone }) => + moment(timestamp).locale(locale).tz(timezone), + formatDuration: ({ duration, format, locale }) => { + const defaultDurationFormat = duration?.includes('H') ? 'h:mm:ss' : 'mm:ss'; + const durationInMilliseconds = moment.duration(duration).asMilliseconds(); + + return moment + .utc(durationInMilliseconds) + .locale(locale) + .format(format || defaultDurationFormat); + }, + // Exposed to make Temporal available at runtime without changing behavior yet. + toTemporalInstant: timestamp => + globalThis.Temporal?.Instant?.fromEpochMilliseconds(timestamp), +}); + +const dateAdapter = createDateAdapter(); + // Note that this next section is globally configuring moment. // It is not possible to configure these on specific moment instances. // The current requirements for rounding & thresholding are the same universally @@ -20,12 +43,11 @@ moment.relativeTimeThreshold('d', 30); moment.relativeTimeThreshold('M', 12); export const formatDuration = ({ duration, format, locale = 'en-gb' }) => { - const defaultDurationFormat = duration?.includes('H') ? 'h:mm:ss' : 'mm:ss'; - const durationInMilliseconds = moment.duration(duration).asMilliseconds(); - return moment - .utc(durationInMilliseconds) - .locale(locale) - .format(format || defaultDurationFormat); + return dateAdapter.formatDuration({ + duration, + format, + locale, + }); }; // if the date is invalid return false - https://stackoverflow.com/questions/1353684/detecting-an-invalid-date-date-instance-in-javascript#answer-1353711 @@ -39,7 +61,10 @@ export const isValidDateTime = dateTime => { // when using the following 2 functions, we recommend using webpack configuration to only load in the relevant timezone, rather than all of moment-timezone export const localisedMoment = ({ locale, timestamp }) => { - return moment(timestamp).locale(locale); + return dateAdapter.createLocalisedMoment({ + locale, + timestamp, + }); }; export const formatUnixTimestamp = ({ @@ -51,7 +76,11 @@ export const formatUnixTimestamp = ({ }) => { if (!timestamp) return undefined; - const momentObj = moment(timestamp).locale(locale).tz(timezone); + const momentObj = dateAdapter.createMomentInTimezone({ + locale, + timestamp, + timezone, + }); if (isRelative) { return momentObj.fromNow(); diff --git a/yarn.lock b/yarn.lock index 39610cba7c4..cc5bf54b616 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15866,6 +15866,7 @@ __metadata: retry: "npm:0.13.1" storybook: "npm:10.3.6" supertest: "npm:7.2.2" + temporal-polyfill: "npm:0.3.0" timemachine: "npm:0.3.2" ts-jest: "npm:29.4.9" typescript: "npm:5.9.3"