⌚ Temporal

Philip Chimento
Igalia, in partnership with Bloomberg
TC39 November 2025

Progress update

  • There are two implementations that pass 99% of the test262 tests.
  • We've hunted down implementation divergences using a snapshot testing technique.
  • Today, we have one normative change to propose, found using snapshot testing.

Test conformance as of November 2025

Engine %PASS Change
SM 99% ↓0.07%
V8 99% ↑0.4%
Kiesel 97% ↑1%
Boa 97% ↑0.3%
Ladybird 96% ↓0.2%
GraalJS 96% ↑6%
JSC 48% ↑7%

Path to Stage 4

  • V8 implementation unflagged in trunk, scheduled for Dec 3 beta and mid-January release
  • Remaining tests in staging are moved to main test262, updated and expanded as needed
  • Identified gaps in test coverage are filled
  • Temporal moves to stage 4, together with Time Zone Canonicalization and Intl Era/Month Code

Test coverage and implementation divergences

  • Introduced a snapshot testing technique
  • Testing millions of combinations of "interesting" inputs
  • Flagging for further inspection when:
    • an assertion fails
    • an assumed invariant does not hold (e.g. a + b = a - -b)
    • results are different between implementations

Check it out!

tc39/proposal-temporal ⋄ polyfill/test/thorough/

./all.sh "$path_to_your_interpreter_with_any_needed_cli_args"

(requires an interpreter with JSON imports support)

Results: worth it!

  • Spec bug: #3168 (more on this shortly)
  • SpiderMonkey bug: #1998020
  • JavaScriptCore bugs: #301659, #301710, #301717, #301724
  • temporal_rs bugs: #610, #613, #617
  • V8 bug unrelated to temporal_rs: #446728405 (already filed but stale; added a current reproducer)
  • GraalJS bugs: Found ≥4 distinct ones. Will open issues soon.
  • Test262: Added specific test coverage for all of these bugs.

More to come

  • We will continue to add more of these snapshot tests
  • Technique may be of interest to other proposal authors

Assertion failure in Duration rounding

> d = Temporal.Duration.from({ years: 1, hours: 1 });
> d.round({ smallestUnit: 'years', relativeTo: '2020-02-29', roundingMode: 'floor' });
  // Current: duration of 0 length (and assertion failure in Firefox debug builds)
  // Proposed: duration of 1 year
  • Duration rounding and totalling uses a "bounding" algorithm
  • We construct two bounding Durations start and end that are multiples of a rounding increment
  • Such that startd < end
  • Round based on whether d is closer to start or end
  • Total based on fraction

Assertion failure in Duration rounding (2)

> d = Temporal.Duration.from({ years: 1, hours: 1 });
> d.round({ smallestUnit: 'years', relativeTo: '2020-02-29', roundingMode: 'floor' });
  // Current: duration of 0 length (and assertion failure in Firefox debug builds)
  // Proposed: duration of 1 year
  • Via snapshot testing, found an edge case
  • Algorithm generates bounds where startd < end does not hold
  • Fix in normative PR #3172
  • h/t Tim Chevalier

Assertion failure in Duration rounding (3)

  • Normative?
  • Usually we say that assertion failures are an editorial error
  • In this case, ignoring assertions can give an incorrect result, which has been exposed to the Web. Thus, normative

Questions?

Requesting consensus

Proposed summary for notes

There are two almost completely conformant implementations, one still flagged. We outlined a path to stage 4 for the proposal and listed the blockers.

...

npx test262-harness --hostType=sm --hostPath=$HOME/.esvu/bin/sm -f Temporal "test/**/*.js" npx test262-harness --hostType=v8 --hostPath=$HOME/.esvu/bin/v8 -f Temporal --hostArgs=--harmony-temporal -- "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=boa --hostPath=$HOME/.esvu/bin/boa-nightly -f Temporal -- "test/**/*.js" # requires https://github.com/tc39/eshost/pull/147 and https://github.com/devsnek/esvu/pull/66 npx test262-harness --hostType=hermes --hostPath=$HOME/.esvu/bin/kiesel-nightly -f Temporal -- "test/**/*.js" npx test262-harness --hostType=graaljs --hostPath=$HOME/.esvu/bin/graaljs -f Temporal --hostArgs='--experimental-options --js.temporal' -- "test/**/*.js" # note: have to kill process on test/staging/sm/Temporal/PlainMonthDay/from-chinese-leap-month-common.js (both strict and sloppy mode) npx test262-harness --hostType=jsc --hostPath=$HOME/.esvu/bin/jsc -f Temporal --hostArgs=--useTemporal=1 -- "test/**/*.js" npx test262-harness --hostType=node --hostPath=$HOME/.local/bin/deno -f Temporal --hostArgs='run --unstable-temporal' -- "test/**/*.js"

"interesting" i.e. chosen to be somewhat likely to find bugs?

There were cases with some inputs where the assertion was hit but the method still produced the correct answer when assertions were switched off in release builds. But there were also cases where it didn't.