⌚ Temporal

Philip Chimento
Igalia, in partnership with Bloomberg
TC39 April 2025

Progress update

Temporal is shipping in Firefox Nightly builds. Some open questions have been raised about coordinating locale-defined behaviour between implementations, which TG2 is addressing. We will continue to analyze code coverage metrics, submit additional
test262 tests, and answer any questions raised.

Test conformance as of April 2025

Engine %PASS Change
SM ~100% ↓0.02%
Ladybird 96% ↓0.4%
GraalJS 91% ↑1.6%
Boa 85% ↑13%
V8 73% ↓0.5%
JSC 40% ↓0.1%

Internal calculations

In the past there were performance concerns about the use of BigInts in the spec. I showed in a previous update that 75 integer bits were enough.

Based on a paper1, I wrote a proof of concept representing epoch nanoseconds and time durations as a pair of 64-bit floats each, so that you don't have to deal with nonstandard-sized integers. Let me know if interested for your implementation.

1 Hida, Li, Bailey (2008). Library for double-double and quad-double arithmetic. Technical report, Lawrence Berkeley National Laboratory. https://www.davidhbailey.com/dhbpapers/qd.pdf

Questions?

Proposed summary for notes

Guidelines for Locale-Sensitive Testing in Test262

Philip Chimento
Igalia
TC39 April 2025

ILD

Implementation- and locale-defined.

new Date().toLocaleString('en', { dayPeriod: 'long' })
// → "in the afternoon"

iii. Let fv be a String value representing the day period of tm in the form given by f; the String value depends upon the implementation and the effective locale of dateTimeFormat.

Stability in ILD behaviour

It's good for users of the web when...

  • ILD behaviour is stable, so that websites don't break
  • ILD behaviour is updated to follow changing cultural practices & better understanding thereof, so that websites are localized in a way that makes users comfortable

These two things are both good, and directly in tension

Test coverage

  • Should it be a goal to cover every combination of locale and options?
  • IMO, no!
  • Diminishing returns, after a certain point you are just testing CLDR

Some existing strategies for ILD testing

(that are not ideal)

  • "Golden" output
  • "Mini-implementation"

Golden output

  • Testing jargon: comparing output of method under test to known-good output
  • Undesirable in test262 because:
    • golden output varies between implementations
    • golden output varies over time
    • variations are permitted by specification
    • test suite can only reasonably be run by an implementation using a specific version of CLDR, and if you aren't using CLDR, forget it

Mini-implementation

  • Including what is essentially a polyfill in the test, comparing its output to that of method under test
  • Undesirable in test262 because:
    • difficult to understand what's being tested
    • unclear whether the polyfill or implementation is at fault when tests fail

But what to do instead?

Stable substrings?

  • Not golden output, but a part of the output that is reasonably expected to be stable
  • More robust than golden output
  • Still shares some disadvantages
const formatter = new Intl.DateTimeFormat("en", { dateStyle: "full" });
const result = formatter.format(new Date(2024, 9, 24, 12));
assert(result.indexOf("October") > -1);

Comparative testing?

  • Each setting for an input option must produce a distinct output
  • Could be good for getting coverage
  • Assumption doesn't hold in all cases
const date = new Date(2024, 9, 24, 12);
const weekdayResults = ["narrow", "short", "long"].map((weekday) => date.toLocaleString("en", { weekday }));
assertNoDuplicates(results);

// BUT:
const dayResults = ["numeric", "2-digit"].map((day) => date.toLocaleString("en", { day }));
assertNoDuplicates(dayResults); // ⚠ fails for days ≥ 10

Metamorphic testing?

  • Find invariant properties of outputs that must hold across multiple inputs
  • No need to specify what those outputs exactly are
  • Can be difficult to find these properties if not specified
const locale = /* any locale, with any calendar or any numbering system */;
const date = new Date(2024, 9, 24, 12);
const dayString = date.toLocaleString(locale, { day: "numeric" });
const monthName = date.toLocaleString(locale, { month: "long" });
const fullDateString = date.toLocaleString(locale, { dateStyle: "full" });
assert(fullDateString.indexOf(dayString) > -1);
assert(fullDateString.indexOf(monthName) > -1);

Discussion

Proposed summary for notes

npx test262-harness --hostType=sm --hostPath=$HOME/workspace/mozilla-unified/obj-debug-x86_64-pc-linux-gnu/dist/bin/js -f Temporal "test/**/*.js" npx test262-harness --hostType=v8 --hostPath=$HOME/.esvu/bin/v8 -f Temporal --hostArgs=--harmony -- "test/**/*.js" npx test262-harness --hostType=libjs --hostPath=$HOME/.esvu/bin/ladybird-js -f Temporal --hostArgs=--use-test262-global -- "test/**/*.js" npx test262-harness --hostType=jsc --hostPath=$HOME/.esvu/bin/jsc -f Temporal --hostArgs=--useTemporal=1 -- "test/**/*.js" npx test262-harness --hostType=boa --hostPath=$HOME/.esvu/bin/boa -f Temporal -- "test/**/*.js" # requires https://github.com/tc39/eshost/pull/147 npx test262-harness --hostType=graaljs --hostPath=$HOME/.esvu/bin/graaljs -f Temporal --hostArgs='--experimental-options --js.temporal' -- "test/**/*.js" npx test262-harness --hostType=node --hostPath=$HOME/.local/bin/deno -f Temporal --hostArgs='run --unstable-temporal' -- "test/**/*.js"