Proposal-temporal: Polyfill crash (in Chrome only) with infinite loop in TimeZone.getAbsoluteFor

Created on 16 May 2020  路  5Comments  路  Source: tc39/proposal-temporal

The polyfill crashes in Chrome with the code below, run in devtools console from https://tc39.es/proposal-temporal/docs/index.html

const date = Temporal.now.date()
const dt = date.withTime(new Temporal.Time())
const tz = Temporal.TimeZone.from('America/Los_Angeles')
const crash = dt.inTimeZone(tz)
Uncaught RangeError: Maximum call stack size exceeded
    at DateTimeFormat.resolvedOptions (<anonymous>)
    at DateTimeFormat.nu [as toString] (ecmascript.mjs:1454)
    at new DateTimeFormat (<anonymous>)
    at Object.GetFormatterParts (ecmascript.mjs:702)
    at Object.GetTimeZoneDateTimeParts (ecmascript.mjs:656)
    at Object.GetTimeZoneOffsetNanoseconds (ecmascript.mjs:589)
    at Object.GetTimeZoneEpochValue (ecmascript.mjs:743)
    at o.value (timezone.mjs:47)
    at o.value (timezone.mjs:81)
    at o.value (timezone.mjs:81)
bug polyfill

Most helpful comment

OK PR is done.

All 5 comments

How bizarre. I can reproduce this using Temporal.DateTime.from('2020-05-18T00:00').inTimeZone('America/Los_Angeles') in Chromium (81) but not in Firefox (75) or Node.js. Not even when loading the bundled polyfill that runs in the web browser: node -r ./out/docs/playground.js

This problem annoyed me so I looked into it. It may have a one-line fix.

The problem is explained well here: https://github.com/formatjs/formatjs/issues/1577#issuecomment-603504717

The root cause is this: https://bugs.chromium.org/p/chromium/issues/detail?id=1045791&q=hourcycle&can=1. There's 10+ dupes already in chromium bugs on this.

The TL;DR: Chrome just started using the DateTimeFormat option hourCycle, which defines 12 vs. 24 behavior as well as whether midnight is 0:00 or 24:00. When hour12: false is set, Chrome defaults to hourCycle: 'h24 which yields 24:00 while other browsers use h23 which gives 00:00.

The Temporal code below breaks when hour==='24' on Chrome.

https://github.com/tc39/proposal-temporal/blob/f49b65dbc2cf7f4eb210a4f35296c05fa4db9139/polyfill/lib/ecmascript.mjs#L701-L727

Here's how I patched it locally. Seems to work well on my Chrome 81.0.4044.138.

// { type: 'hour', value: +hour },
{ type: 'hour', value: hour === '24' ? 0 : +hour }, // https://bugs.chromium.org/p/chromium/issues/detail?id=1045791

Here's a minimal repro.

// Broken in chrome where default midnight in en locales is "24:00"
// because setting hour12=false sets hourCycle to h24, not h23 as expected.
// https://bugs.chromium.org/p/chromium/issues/detail?id=1045791
console.log(
  new Intl.DateTimeFormat('en-us', {
    timeZone: 'Europe/London',
    hour12: false,
    era: 'short',
    year: 'numeric',
    month: 'numeric',
    day: 'numeric',
    hour: 'numeric',
    minute: 'numeric',
    second: 'numeric',
  }).format(1589670000000)
);

// Here's how to force hourCycle=h23 in Chrome. You've
// gotta remove the hour12 setting. But doing that
// messes things up in Firefox. It's probably easiest
// to just look for hour===24 and reset it to zero.
console.log(
  new Intl.DateTimeFormat('en-us', {
    timeZone: 'Europe/London',
    //  hour12: false,
    hourCycle: 'h23',
    era: 'short',
    year: 'numeric',
    month: 'numeric',
    day: 'numeric',
    hour: 'numeric',
    minute: 'numeric',
    second: 'numeric',
  }).format(1589670000000)
);

@justingrant Would you like to make a PR for this?

Sure. For some reason I can't get any of the test suites to run locally on my Mac, so I'll have to depend on CI to run tests. I'll push the test changes first to validate that the test breaks, then push the code changes and hope for the best! ;-)

OK PR is done.

Was this page helpful?
0 / 5 - 0 ratings