Skip to content

Normative: Temporal stage 4#3759

Open
ptomato wants to merge 18 commits intotc39:mainfrom
ptomato:temporal-stage-4
Open

Normative: Temporal stage 4#3759
ptomato wants to merge 18 commits intotc39:mainfrom
ptomato:temporal-stage-4

Conversation

@ptomato
Copy link
Contributor

@ptomato ptomato commented Feb 16, 2026

Stage 4 PR for Temporal.

Draft 2026-02-16: This currently includes only the changes to ECMA-262 that would need to be made if putting Temporal in a separate document. It does not yet include the Temporal Object itself. I've posted this for early feedback since I expect these parts will be what attracts the most review comments anyway. I'll update this later on to include the rest of the proposal.

2026-02-20: This now includes the rest of the Temporal proposal.

@ptomato ptomato marked this pull request as draft February 16, 2026 23:53
Copy link
Contributor Author

@ptomato ptomato left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Self-reviewing to point out places where you might particularly have questions/comments and places where the one-document approach would simplify things.

We may want to additionally look at https://tc39.es/ecma262/#sec-date-time-string-format. Most likely this can be simplified with Temporal stuff, or turned into a grammar using the building blocks from Temporal's RFC9557 grammar.

spec.html Outdated
In time zone aware implementations, a primary time zone identifier is a Zone name, and a non-primary time zone identifier is a Link name, respectively, in the IANA Time Zone Database except as specifically overridden by AvailableNamedTimeZoneIdentifiers as specified in the ECMA-402 specification.
Implementations that do not support the entire IANA Time Zone Database are still recommended to use IANA Time Zone Database names as identifiers to represent time zones.
</p>
<p>These identifiers are described by the following grammar.</p>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This grammar would be deduplicated into Temporal's RFC 9557 grammar if we go the same-document route.

spec.html Outdated
UTC offsets that represent offset time zone identifiers, or that are intended for interoperability with ISO 8601, use only hours and minutes and are specified by |UTCOffset[~SubMinutePrecision]|.
UTC offsets that represent the offset of a named time zone can be more precise, and are specified by |UTCOffset[+SubMinutePrecision]|.
</p>
<p>These formats are described by the following grammar.</p>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This grammar would also be deduplicated into Temporal's RFC 9557 grammar.

spec.html Outdated
</emu-clause>
</emu-clause>

<emu-clause id="sec-iso-date-records">
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These three sections on ISO Date Records, Time Records, and ISO Date-Time Records would go into a Temporal section if we put Temporal in the same document. But they're needed in ECMA-262 for AOs like GetNamedTimeZoneEpochNanoseconds and GetNamedTimeZoneOffsetNanoseconds.

@ptomato ptomato force-pushed the temporal-stage-4 branch 2 times, most recently from b7627f5 to 283e9b8 Compare February 17, 2026 00:25
@ptomato
Copy link
Contributor Author

ptomato commented Feb 17, 2026

As for the "esmeta yet phrases detection" job there seem to be two main issues:

  • ESMeta seems not to ignore steps beginning with "NOTE:"
  • ESMeta seems not to understand "an integer in the inclusive interval from X to Y"

I'm puzzled about that since both constructions seem to be used elsewhere in the spec. Am I doing something wrong here or do I need to add these manually to a skip list?

Once those are resolved I can dig into the remaining items turned up by ESMeta.

@michaelficarra michaelficarra added the editor call to be discussed in the next editor call label Feb 17, 2026
This commit makes changes to ECMA-262 AOs that are needed for Temporal
regardless of whether it lands in a separate document.
This adds the rest of the Temporal proposal, organizing it into the
"Numbers and Dates" section. Some of the sections added in the previous
commit are moved into Temporal sections.

The existing section on "Time Zone Identifiers", used both by Date and
Temporal, is moved into its own section under "Numbers and Dates".

Most of the proposal is kept in separate temporal/*.emu files, included
with `<emu-import>` tags. This is an arbitrary choice and can be done
differently if so desired.
Copy link
Contributor Author

@ptomato ptomato left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More self-review with comments on things you may want to look at. I'm planning to join the editor call on Monday 23 Feb, so we can talk through this PR live.

Additional comments not tied to a particular place in the PR:

  • We may want to refactor/rewrite 21.4.1.32 Date Time String Format to use the new grammar.
  • Probably one of the main things to talk about in the editor call is "how to structure the sections". I've put most everything as subsections of the "Numbers and Dates" section. Maybe it makes sense to split that up into two toplevel sections, "Numbers" and "Dates"? Here's what the second-level outline looks like now:
Image

Comment on lines +469 to +486
<emu-clause id="sec-canonicalizeuvalue" type="abstract operation">
<h1>
CanonicalizeUValue (
_ukey_: a Unicode locale extension sequence key defined in <a href="https://unicode.org/reports/tr35/#Key_And_Type_Definitions_">Unicode Technical Standard #35 Part 1 Core Section 3.6.1 Key and Type Definitions</a>,
_uvalue_: a String,
): a String
</h1>
<dl class="header">
<dt>description</dt>
<dd>The returned String is the canonical and case-regularized form of _uvalue_ as a value of _ukey_.</dd>
</dl>
<emu-alg>
1. Let _lowerValue_ be the ASCII-lowercase of _uvalue_.
1. Let _canonicalized_ be the String value resulting from canonicalizing _lowerValue_ as a value of key _ukey_ per <a href="https://unicode.org/reports/tr35/#processing-localeids">Unicode Technical Standard #35 Part 1 Core, Annex C LocaleId Canonicalization Section 5 Canonicalizing Syntax, Processing LocaleIds</a>.
1. NOTE: It is recommended that implementations use the 'u' extension data in <code>common/bcp47</code> provided by the Common Locale Data Repository (available at <a href="https://cldr.unicode.org/">https://cldr.unicode.org/</a>).
1. Return _canonicalized_.
</emu-alg>
</emu-clause>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CanonicalizeUValue is debatable whether it should be included here. It's moved from ECMA-402 into here, but is only used for CanonicalizeCalendar, to show that if the implementation supports multiple calendars, their identifiers should be canonicalized in the way specified in UTS#35.

An alternative would be to override CanonicalizeCalendar in ECMA-402 instead, and provide a skeleton CanonicalizeCalendar here which does something like "If id is some case-insensitive form of "iso8601", return "iso8601", else throw".

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've included what this would look like, in an additional commit named "(optional) Change approach for specifying CanonicalizeCalendar".

@ptomato ptomato marked this pull request as ready for review February 20, 2026 19:20
@Jack-Works
Copy link
Member

Hi! I'm implementing Temporal in engine262. I'd like to know if all changes made here will be synced to the Temporal repo, or if the repo will be stale and all new changes will be made here.

@ptomato
Copy link
Contributor Author

ptomato commented Feb 23, 2026

I'm not planning to sync changes back to the Temporal repo, unless someone really wants that.

@bakkot bakkot added the request preview ask the bot to trigger a PR preview label Feb 23, 2026
@github-actions github-actions bot removed the request preview ask the bot to trigger a PR preview label Feb 23, 2026
@github-actions
Copy link

The rendered spec for this PR is available as a single page at https://tc39.es/ecma262/pr/3759 and as multiple pages at https://tc39.es/ecma262/pr/3759/multipage .

@bakkot
Copy link
Member

bakkot commented Feb 23, 2026

Notes from editor call:

  • let's put Dates+Temporal in their own section, and reduce the current Numbers and Dates section to just Number/BigInt/Math
  • Date.parse is no longer strictly a simplification of ISO 8601 as 8601 no longer allows "24" for hours; as this PR is updating the referenced version of 8601, we should add some wording to that effect
  • GetOption is overkill, at least for base64, and it can probably be inlined into all of its callsites in Temporal
  • [[EpochNanoseconds]] should be a mathematical value instead of a BigInt, both as a matter of convention and because implementations are likely to use a different type than their internal bigint type
  • the algorithm in AddTimeDurationToEpochNanoseconds is written with the values backwards from the order in which they appear as parameters, which is confusing even though it doesn't actually affect anything
  • don't worry about esmeta for now
  • we are undecided on how to handle CanonicalizeCalendar (personally I am fine with the current approach, or for doing something like we do for timezones, as in, we can say here's the implementation if you only support iso8601, otherwise you must use the implementation from 402)

Split the "Numbers and Dates" section into "Numbers and Mathematical
Functions" and "Dates and Temporal".
…rmat

24:00 is not supported in the current (2019) edition of ISO 8601, unlike
the 2004 edition which we previously cited in the bibliography. Also
update the note about a standard for time zone names not existing; this
exists now with RFC 9557.
The desired convention going forward ("Stop Coercing Things") is too
different from the ECMA-402 options conventions, so it doesn't make
sense to share GetOption with ECMA-402.

The reversion of base64 changes can be squashed with "Normative:
Temporal stage 4, part 1"
Minor editorial point, reads better when the operands are in the same
order as the AO's arguments.
[[EpochNanoseconds]] should be a mathematical value instead of a BigInt,
both as a matter of convention and because implementations are likely
to use a different type than their internal BigInt type.

Bikeshedding welcome on the type name. I went with "An epoch nanoseconds
value", but "an exact time", "an epoch time", etc., are possibilities.
Can be squashed with "Normative: Temporal stage 4, part 2"
…rings

Instead of |DateYear| and |DateDay|. Naming the parse node one level
down from the goal may make it easier to understand what needs to be
implemented.
As discussed during the editors meeting, this commit shows what it'd
look like if we changed AvailableCalendars and CanonicalizeCalendar to
work more like time zones, where we give the specification assuming that
only the minimum is supported.

CanonicalizeUValue would then stay in ECMA-402 where it originated, and
ECMA-402 would gain an override of CanonicalizeCalendar (it already has
one for AvailableCalendars).
@ptomato ptomato added the request preview ask the bot to trigger a PR preview label Feb 25, 2026
@github-actions github-actions bot removed the request preview ask the bot to trigger a PR preview label Feb 25, 2026
@ptomato
Copy link
Contributor Author

ptomato commented Feb 25, 2026

I've added commits addressing all the things we discussed in Monday's editor call. (To make it easy to see what changed, I'll refrain from squashing or force-pushing until it comes time to merge.)

I tried to request another preview but the job failed with a 403 on npm ci, so not sure what's going on there.

@ptomato
Copy link
Contributor Author

ptomato commented Feb 25, 2026

I've added commits addressing all the things we discussed in Monday's editor call. (To make it easy to see what changed, I'll refrain from squashing or force-pushing until it comes time to merge.)

I tried to request another preview but the job failed with a 403 on npm ci, so not sure what's going on there.

ptomato added a commit to ptomato/ecma402 that referenced this pull request Feb 25, 2026
…ndar

See the commit named "(optional) Change approach for specifying
CanonicalizeCalendar" in tc39/ecma262#3759 -
pending discussion with the ECMA-262 editors.
@gibson042 gibson042 added the request preview ask the bot to trigger a PR preview label Feb 26, 2026
@github-actions github-actions bot removed the request preview ask the bot to trigger a PR preview label Feb 26, 2026
ptomato added a commit to ptomato/ecma402 that referenced this pull request Feb 26, 2026
See the commit named "(review) Express epoch nanoseconds in mathematical
values" in tc39/ecma262#3759 - this change is
based on feedback from the ECMA-262 editors that epoch time should be
specified as mathematical values.
Copy link
Member

@gibson042 gibson042 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Partial review, mostly just spec.html.

@bakkot Note that ISO 8601 does allow "24" for hours again as of 2022.

<dl class="header">
<dt>description</dt>
<dd>The return value indicates whether _offsetString_ conforms to the grammar given by |UTCOffset|.</dd>
<dd>The return value indicates whether _offsetString_ conforms to the grammar given by |UTCOffset[~SubMinutePrecision]|.</dd>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This restriction is technically a breaking change, although I think we failed to find any implementation for which SystemTimeZoneIdentifier returned an offset string with sub-minute precision. So I don't know whether or not a mention belongs in Annex F.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alternatively we could just make this |UTCString[+SubMinutePrecision]| here, although we'd have to check callers of the operation to see if any further validation was needed.

The ISO 8601-1:2019/Amd.1:2022 amendment added back support for 24:00,
this time even as an instant in time and not just the end of a duration.
(And, while here, fix the descriptions at the very top of each section
--- these were seriously outdated)
Not sure why I thought this was supposed to be alphabetized; the other
sections aren't.
@ptomato ptomato changed the title Draft: Normative: Temporal stage 4 Normative: Temporal stage 4 Feb 27, 2026
Review suggestion from Michael Dyck.
@michaelficarra michaelficarra added the request preview ask the bot to trigger a PR preview label Mar 5, 2026
@github-actions github-actions bot removed the request preview ask the bot to trigger a PR preview label Mar 5, 2026
This was a confusion on my part because in implementations you can
optimize out the weeks and days parameters entirely.

h/t Jack Works
@ptomato
Copy link
Contributor Author

ptomato commented Mar 5, 2026

Pushed another commit addressing a comment from @Jack-Works (tc39/proposal-temporal#3290)

Comment on lines +366 to +367
<emu-clause id="sec-rfc9557grammar-static-semantics-early-errors">
<h1>Static Semantics: Early Errors</h1>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we're missing a syntax error for |TimeZoneIANAName| productions when |TimeZoneIANANameComponent| is "." or "..", which should be added for alignment with RFC 9557.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it matters that much, since an annotation like [../../Foobar] will throw a RangeError anyway when given to Instant.from() or ZonedDateTime.from(), because there won't be an IANA time zone with that name.

But note that it would technically be a normative change to make it into a syntax error, because Temporal.PlainDate.from('2026-03-06T15[../../Foobar]') would throw an error instead of ignoring the annotation (as it would with an otherwise syntactically valid annotation such as Temporal.PlainDate.from('2026-03-06T15[Europe/Custom]')).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've pushed a commit marked "(optional)" implementing this, if we choose to go ahead with it. But I'd personally recommend against at this point.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer you not include that commit in this PR unless you're planning to ask for consensus for the normative change.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

editor call to be discussed in the next editor call

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants