⌚ Temporal

Philip Chimento
Igalia, in partnership with Bloomberg
TC39 February 6–8, 2024

Progress update

  • Backlog of approved normative changes is all caught up
  • 4 normative changes proposed today for bugs found during implementation, polyfilling, or community use
    • Narrowly scoped: edge cases with minimal implementer impact
    • Will merge after this meeting
  • NOT an indication of more changes coming
    • No more known outstanding bugs
    • Last normative changes were in Nov 2023 (bugfix) and July 2023
    • Next one... never?

Progress update (2)

  • Next: finalize any editorial changes that implementors might find disruptive
  • Will give a loud signal when this is done
  • Expect this soon
  • Follow the checklist in #2628 for updates

weekOfYear/yearOfWeek optional (PR #2756)

  • Reported by early adopters
  • Some calendars have week numbers, some don't
  • Prior art: some calendars have eras, some don't
    • Dates' era and eraYear readonly properties may be undefined
  • Proposal
    • Allow weekOfYear and yearOfWeek readonly properties to be undefined
    • Calendars may return undefined from weekOfYear() and yearOfWeek() methods

Notes for specifying calendars

  • Which calendars have week numbers and how are they numbered?
  • ECMAScript does not have to specify this
  • Data will come from CLDR and ICU
  • However, may be in scope of the Intl Era and Month Codes proposal
  • See tc39/proposal-intl-era-monthcode#15

Duration rounding bug (PR #2758)

  • Reported by Adam Shaw (polyfill author)
const duration = Temporal.Duration.from({years: 1, hours: 24});
const past = Temporal.ZonedDateTime.from("2019-11-01T00:00-07:00[America/Vancouver]");
const future = past.add(duration);  // 2020-11-01T23:00-08:00[America/Vancouver]
  // (note, not 2020-11-02, because 2020-11-01 is a 25-hour day in that time zone)

past.until(future, {largestUnit: 'years'})  // 1 year, 24 hours (CORRECT)
duration.round({largestUnit: 'years', relativeTo: past})  // 1 year, 1 day (WRONG)
  • In round, the wrong reference date was used

Duration rounding bug (2)

  • Generalizing, these should always be equivalent:
past.until(past.add(duration), { largestUnit, smallestUnit, roundingMode, etc })
duration.round({ relativeTo: past, largestUnit, smallestUnit, roundingMode, etc })
  • Today, results disagree if past is a Temporal.ZonedDateTime and a DST change happens on past + date part of duration
  • Fix bug + refactor spec to unify codepath for both operations
  • Prevents future discrepancies

ZonedDateTime difference bug (PR #2760)

  • Reported by Adam Shaw (polyfill author)
const duration = Temporal.Duration.from({ months: 1, days: 15, hours: 12 });
const past = Temporal.ZonedDateTime.from('2024-02-10T02:00[America/New_York]');
const future = past.add(duration);
past.until(future, { largestUnit: 'months' })  // => 1 month, 15 days, 11 (!) hours
  • Above: DST disambiguation happened at the month/day boundary, but should have been ignored
  • DST disambiguation only expected at the day/hour boundary
  • Narrowly-scoped fix to ZDT addition algorithm

End-of-month edge cases (PR #2759)

  • From André Bargull (Firefox impl.) and Adam Shaw (polyfill author)
  • Unexpected since/until result near end of month
const end = new Temporal.PlainDate(1970, 2, 28);
new Temporal.PlainDate(1970, 1, 28).until(end, {largestUnit:"months"})  // "1 month"
new Temporal.PlainDate(1970, 1, 29).until(end, {largestUnit:"months"})  // "1 month"
new Temporal.PlainDate(1970, 1, 30).until(end, {largestUnit:"months"})  // "1 month"
new Temporal.PlainDate(1970, 1, 31).until(end, {largestUnit:"months"})  // "1 month"
  • Expected (e.g. java.time): 1 month, 30 days, 29 days, 28 days resp.
  • Affects largestUnit: 'months'|'years' (default options are OK)
  • Narrow scope: one-line change affects only 0.2% of date pairs

Questions?

Requesting consensus

On normative PRs #2756, #2758, #2759, #2760

Proposed summary for notes

Consensus was reached on a normative change making week numbering optional for calendars (PR #2756), a normative change to fix a bug in duration rounding (PR #2758), a normative change to return more useful results from date differences in end-of-month edge cases (#2759), and a normative change to fix a bug in ZonedDateTime differences (PR #2760) reached consensus.
The proposal champions are not aware of any further outstanding bugs, and expect implementations to be able to use the proposal as a stable base in the coming weeks with only editorial changes expected. Follow the checklist in #2628 for updates.

We believe this is consistent with what we promised in July