Skip to content

Commit

Permalink
Speed up TimeZone and ZonedDateTime code and tests
Browse files Browse the repository at this point in the history
Creating Intl.DateTimeFormat instances in V8 is slow and memory heavy.
GetFormatterParts and GetCanonicalTimeZoneIdentifier are functions that
are called many times when using Temporal, and they used to create new
instances of Intl.DateTimeFormat for each call. In this commit, we cache
them using the time zone identifier as the key.

It should be noted that doing the same to SystemTimeZone was
avoided. This is due to the fact that user's time zone may change during
the execution of a program. An example: Temporal.now.zonedDateTimeISO()
should always output the correct time zone. This shouldn't be a problem
for server-side code that usually doesn't (or rather, shouldn't) use
the time zone from the environment for calculations.

(ported from js-temporal/temporal-polyfill#10)
  • Loading branch information
justingrant committed Jul 10, 2021
1 parent 44995c7 commit 48f6c83
Showing 1 changed file with 23 additions and 21 deletions.
44 changes: 23 additions & 21 deletions polyfill/lib/ecmascript.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,27 @@ const ES2020 = {
Type
};

const IntlDateTimeFormatEnUsCache = new Map();

function getIntlDateTimeFormatEnUsForTimeZone(timeZoneIdentifier) {
let instance = IntlDateTimeFormatEnUsCache.get(timeZoneIdentifier);
if (instance === undefined) {
instance = new IntlDateTimeFormat('en-us', {
timeZone: String(timeZoneIdentifier),
hour12: false,
era: 'short',
year: 'numeric',
month: 'numeric',
day: 'numeric',
hour: 'numeric',
minute: 'numeric',
second: 'numeric'
});
IntlDateTimeFormatEnUsCache.set(timeZoneIdentifier, instance);
}
return instance;
}

export const ES = ObjectAssign({}, ES2020, {
ToPositiveInteger: ToPositiveInteger,
ToFiniteInteger: (value) => {
Expand Down Expand Up @@ -2081,16 +2102,7 @@ export const ES = ObjectAssign({}, ES2020, {
GetCanonicalTimeZoneIdentifier: (timeZoneIdentifier) => {
const offsetNs = ES.ParseOffsetString(timeZoneIdentifier);
if (offsetNs !== null) return ES.FormatTimeZoneOffsetString(offsetNs);
const formatter = new IntlDateTimeFormat('en-us', {
timeZone: String(timeZoneIdentifier),
hour12: false,
year: 'numeric',
month: 'numeric',
day: 'numeric',
hour: 'numeric',
minute: 'numeric',
second: 'numeric'
});
const formatter = getIntlDateTimeFormatEnUsForTimeZone(String(timeZoneIdentifier));
return formatter.resolvedOptions().timeZone;
},
GetIANATimeZoneOffsetNanoseconds: (epochNanoseconds, id) => {
Expand Down Expand Up @@ -2209,17 +2221,7 @@ export const ES = ObjectAssign({}, ES2020, {
return result;
},
GetFormatterParts: (timeZone, epochMilliseconds) => {
const formatter = new IntlDateTimeFormat('en-us', {
timeZone,
hour12: false,
era: 'short',
year: 'numeric',
month: 'numeric',
day: 'numeric',
hour: 'numeric',
minute: 'numeric',
second: 'numeric'
});
const formatter = getIntlDateTimeFormatEnUsForTimeZone(timeZone);
// FIXME: can this use formatToParts instead?
const datetime = formatter.format(new Date(epochMilliseconds));
const [date, fullYear, time] = datetime.split(/,\s+/);
Expand Down

0 comments on commit 48f6c83

Please sign in to comment.