Skip to content

Commit d983dfa

Browse files
committed
Editorial: Refactor time zone identifier spec text
This commit builds on the new ECMA-262 text for time zone identifiers that was introduced in tc39/ecma262#3035. This commit adds Temporal-specific AOs and makes a handful of edits to ECMA-262 AOs for changes that didn't apply to %Date% but that will be required after Temporal is merged into ECMA-262. This commit also revises the ASCII-case-insensitive section to address feedback from ECMA-262 editors before this text was removed from tc39/ecma262#3035: * Remove the "sequence of code points" info because only Strings seemed to use these definitions. * Minor wordsmithing, e.g. "string value" => "String"
1 parent f487252 commit d983dfa

File tree

6 files changed

+262
-176
lines changed

6 files changed

+262
-176
lines changed

package-lock.json

Lines changed: 7 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
},
99
"main": "polyfill/lib/index.mjs",
1010
"devDependencies": {
11-
"@tc39/ecma262-biblio": "=2.1.2576",
11+
"@tc39/ecma262-biblio": "=2.1.2577",
1212
"@typescript-eslint/eslint-plugin": "^5.59.9",
1313
"@typescript-eslint/parser": "^5.59.9",
1414
"ecmarkup": "^17.0.0",

spec/intl.html

Lines changed: 133 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ <h1>Amendments to the ECMAScript® 2023 Internationalization API Specification</
88
<p>
99
This section lists amendments which must be made to <a href="https://tc39.es/ecma402/">ECMA-402, the ECMAScript® 2023 Internationalization API Specification</a>.
1010
Text to be added is marked <ins>like this</ins>, and text to be deleted is marked <del>like this</del>.
11+
Blocks of unmodified text between modified sections are marked by [...].
1112
</p>
1213
<p>
1314
This text is based on top of the ECMA-402 spec text from commit <a href="https://github.com/tc39/ecma402/commit/eb81befe8b739f976a3d6e68ec567302c4e217f0">eb81befe8b739f976a3d6e68ec567302c4e217f0</a>.
@@ -40,15 +41,89 @@ <h1><a href="https://tc39.es/ecma402/#sec-case-sensitivity-and-case-mapping">Cas
4041
</del>
4142
</emu-clause>
4243

43-
<emu-clause id="sup-time-zone-names">
44-
<h1><a href="https://tc39.es/ecma402/#sec-time-zone-names">Time Zone Names</a></h1>
44+
<ins class="block">
45+
<emu-clause id="sec-use-of-iana-time-zone-database" oldids="sec-time-zone-names">
46+
<h1>Use of the IANA Time Zone Database</h1>
4547

46-
<ins class="block">
48+
<emu-note type="editor">This section replaces the <a href="https://tc39.es/ecma-402/#sec-time-zone-names">Time Zone Names</a> section in ECMA-402.</emu-note>
49+
<p>
50+
Implementations that adopt the ECMAScript Internationalization API Specification are time zone aware: they use the IANA Time Zone Database <a href="https://www.iana.org/time-zones/">https://www.iana.org/time-zones/</a> to supply time zone identifiers and data used in ECMAScript calculations and formatting.
51+
This section defines how the IANA Time Zone Database should be used by time zone aware implementations.
52+
</p>
53+
<p>
54+
Except as overridden by AvailableNamedTimeZoneIdentifiers, each Zone in the IANA Time Zone Database must be a primary time zone identifier and each Link name in the IANA Time Zone Database must be a non-primary time zone identifier.
55+
No String may be an available named time zone identifier unless it is a Zone name or a Link name in the IANA Time Zone Database.
56+
Available named time zone identifiers returned by ECMAScript built-in objects must use the casing found in the IANA Time Zone Database.
57+
</p>
58+
<p>
59+
In the IANA Time Zone Database, the UTC time zone is represented by the Zone *"Etc/UTC"* which is distinct from the Zone *"Etc/GMT"*.
60+
For historical reasons, ECMAScript uses *"UTC"* as the primary identifier for the former Zone and does not recognize the latter Zone as distinct, instead requiring *"Etc/UTC"*, *"Etc/GMT"*, and *"GMT"* (if available) to be non-primary identifiers that resolve to *"UTC"*.
61+
This is the only deviation from the IANA Time Zone Database that is required of a time zone aware ECMAScript implementation.
62+
</p>
63+
<p>
64+
The IANA Time Zone Database is typically updated between five and ten times per year.
65+
These updates may add new Zone or Link names, may change Zones to Links, and may change the UTC offsets and transitions associated with any Zone.
66+
ECMAScript implementations are recommended to include updates to the IANA Time Zone Database as soon as possible.
67+
Such prompt action ensures that ECMAScript programs can accurately perform time-zone-sensitive calculations and can use newly-added available named time zone identifiers supplied by external input or the host environment.
68+
</p>
69+
<p>
70+
If implementations revise time zone information during the lifetime of an agent, then which identifiers are supported, the primary time zone identifier associated with any identifier, and the UTC offsets and transitions associated with any Zone, must be consistent with results previously observed by that agent.
71+
Due to the complexity of supporting this requirement, it is recommended that implementations maintain a fully consistent copy of the IANA Time Zone Database for the lifetime of each agent.
72+
</p>
73+
74+
<p>This section complements but does not supersede <emu-xref href="#sec-time-zone-identifiers"></emu-xref>.</p>
75+
76+
<emu-note>
4777
<p>
48-
<emu-xref href="#sec-time-zone-names"></emu-xref> defines a set of abstract operations concerning the names of supported time zones.
49-
This section introduces additional requirements on these operations for implementations.
78+
The IANA Time Zone Database offers build options that affect which time zone identifiers are primary.
79+
The default build options merge different countries' time zones, for example *"Atlantic/Reykjavik"* being a Link to the Zone *"Africa/Abidjan"*.
80+
Geographically and politically distinct locations are likely to introduce divergent time zone rules in a future version of the IANA Time Zone Database.
81+
Therefore, it is recommended that ECMAScript implementations instead use build options such as <code>PACKRATDATA=backzone PACKRATLIST=zone.tab</code> or a similar alternative that ensures at least one primary identifier for each <a href="https://www.iso.org/glossary-for-iso-3166.html">ISO 3166-1 Alpha-2</a> country code.
5082
</p>
51-
</ins>
83+
</emu-note>
84+
85+
<emu-clause id="sup-availablenamedtimezoneidentifiers" oldids="sec-availabletimezones" type="implementation-defined abstract operation">
86+
<h1>AvailableNamedTimeZoneIdentifiers ( ): a List of Time Zone Identifier Records</h1>
87+
<dl class="header">
88+
<dt>description</dt>
89+
<dd>
90+
Its result describes all available named time zone identifiers in this implementation, as well as the primary time zone identifier corresponding to each available named time zone identifier.
91+
The List is ordered according to the [[Identifier]] field of each Time Zone Identifier Record.
92+
</dd>
93+
<dt>redefinition</dt>
94+
<dd>true</dd>
95+
</dl>
96+
<p>This definition supersedes the definition provided in <emu-xref href="#sec-availablenamedtimezoneidentifiers"></emu-xref>.</p>
97+
<emu-alg>
98+
1. Let _identifiers_ be a List containing the String value of each Zone or Link name in the IANA Time Zone Database.
99+
1. Assert: No element of _identifiers_ is an ASCII-case-insensitive match for any other element.
100+
1. Assert: Every element of _identifiers_ identifies a Zone or Link name in the IANA Time Zone Database.
101+
1. Set _identifiers_ to SortStringListByCodeUnit(_identifiers_).
102+
1. Let _result_ be a new empty List.
103+
1. For each element _identifier_ of _identifiers_, do
104+
1. Let _primary_ be _identifier_.
105+
1. If _identifier_ is a non-primary time zone identifier and _identifier_ is not *"UTC"*, then
106+
1. Set _primary_ to the name of the primary time zone identifier that _identifier_ resolves to, according to the rules for resolving Link names in the IANA Time Zone Database.
107+
1. NOTE: An implementation may need to resolve _identifier_ iteratively to obtain the primary time zone identifier.
108+
1. If _primary_ is one of *"Etc/UTC"*, *"Etc/GMT"*, or *"GMT"*, set _primary_ to *"UTC"*.
109+
1. Let _record_ be the Time Zone Identifier Record { [[Identifier]]: _identifier_, [[PrimaryIdentifier]]: _primary_ }.
110+
1. Append _record_ to _result_.
111+
1. Assert: _result_ contains a Time Zone Identifier Record _r_ such that _r_.[[Identifier]] is *"UTC"* and _r_.[[PrimaryIdentifier]] is *"UTC"*.
112+
1. Return _result_.
113+
</emu-alg>
114+
115+
<emu-note>
116+
Time zone identifiers in the IANA Time Zone Database can change over time.
117+
At a minimum, it is recommended that implementations limit changes to the result of AvailableNamedTimeZoneIdentifiers to the changes allowed by GetAvailableNamedTimeZoneIdentifier, for the lifetime of the surrounding agent.
118+
Due to the complexity of supporting these recommendations, it is recommended that the result of AvailableNamedTimeZoneIdentifiers remains the same for the lifetime of the surrounding agent.
119+
</emu-note>
120+
</emu-clause>
121+
</emu-clause>
122+
</ins>
123+
124+
<del class="block">
125+
<emu-clause id="sec-time-zone-names-deleted">
126+
<h1>Time Zone Names</h1>
52127

53128
<p>
54129
The ECMAScript 2023 Internationalization API Specification identifies time zones using the Zone and Link names of the IANA Time Zone Database. Their canonical form is the corresponding Zone name in the casing used in the IANA Time Zone Database except as specifically overridden by CanonicalizeTimeZoneName.
@@ -58,70 +133,71 @@ <h1><a href="https://tc39.es/ecma402/#sec-time-zone-names">Time Zone Names</a></
58133
A conforming implementation must recognize *"UTC"* and all other Zone and Link names (and <strong>only</strong> such names), and use best available current and historical information about their offsets from UTC and their daylight saving time rules in calculations. However, the set of combinations of time zone name and language tag for which localized time zone names are available is implementation dependent.
59134
</p>
60135

61-
<del class="block">
62-
<emu-clause id="sup-isvalidtimezonename">
63-
<h1><a href="https://tc39.es/ecma402/#sec-isvalidtimezonename">IsValidTimeZoneName</a> ( _timeZone_ )</h1>
136+
<emu-clause id="sec-isvalidtimezonename" aoid="IsValidTimeZoneName">
137+
<h1><a href="https://tc39.es/ecma402/#sec-isvalidtimezonename">IsValidTimeZoneName</a> ( _timeZone_ )</h1>
64138

65-
<p>
66-
The abstract operation IsValidTimeZoneName takes argument _timeZone_, a String value, and verifies that it represents a valid Zone or Link name of the IANA Time Zone Database.
67-
</p>
139+
<p>
140+
The abstract operation IsValidTimeZoneName takes argument _timeZone_, a String value, and verifies that it represents a valid Zone or Link name of the IANA Time Zone Database.
141+
</p>
68142

69-
<emu-alg>
70-
1. If one of the Zone or Link names of the IANA Time Zone Database is an ASCII-case-insensitive match of _timeZone_, return *true*.
71-
1. If _timeZone_ is an ASCII-case-insensitive match of *"UTC"*, return *true*.
72-
1. Return *false*.
73-
</emu-alg>
74-
</emu-clause>
75-
</del>
143+
<emu-alg>
144+
1. If one of the Zone or Link names of the IANA Time Zone Database is an ASCII-case-insensitive match of _timeZone_, return *true*.
145+
1. If _timeZone_ is an ASCII-case-insensitive match of *"UTC"*, return *true*.
146+
1. Return *false*.
147+
</emu-alg>
148+
</emu-clause>
76149

77-
<emu-clause id="sup-canonicalizetimezonename" type="abstract operation">
150+
<emu-clause id="sec-canonicalizetimezonename" type="abstract operation">
78151
<h1>
79152
CanonicalizeTimeZoneName (
80-
_timeZone_: a String value that is <del>a valid</del><ins>an available</ins> time zone name as verified by <del>IsValidTimeZoneName</del><ins>IsAvailableTimeZoneName</ins>,
153+
_timeZone_: a String value that is a valid time zone name as verified by IsValidTimeZoneName,
81154
)
82155
</h1>
83156
<dl class="header">
84157
<dt>description</dt>
85158
<dd>It returns the canonical and case-regularized form of _timeZone_.</dd>
86-
<dt>redefinition</dt>
87-
<dd>true</dd>
88159
</dl>
89-
90160
<emu-alg>
91161
1. Let _ianaTimeZone_ be the String value of the Zone or Link name of the IANA Time Zone Database that is an ASCII-case-insensitive match of _timeZone_.
92162
1. If _ianaTimeZone_ is a Link name, let _ianaTimeZone_ be the String value of the corresponding Zone name as specified in the file <code>backward</code> of the IANA Time Zone Database.
93163
1. If _ianaTimeZone_ is *"Etc/UTC"* or *"Etc/GMT"*, return *"UTC"*.
94164
1. Return _ianaTimeZone_.
95165
</emu-alg>
166+
</emu-clause>
96167

97-
<ins class="block">
98-
<p>This definition supersedes the definition provided in <emu-xref href="#sec-canonicalizetimezonename"></emu-xref>.</p>
99-
</ins>
168+
<emu-clause id="sup-defaulttimezone" oldids="sec-defaulttimezone" type="implementation-defined abstract operation">
169+
<h1>DefaultTimeZone ( ): a String</h1>
170+
171+
<dl class="header">
172+
<dt>description</dt>
173+
<dd>It returns a String value representing the host environment's current time zone, which is a valid (<emu-xref href="#sec-isvalidtimezonename"></emu-xref>) and canonicalized (<emu-xref href="#sec-canonicalizetimezonename"></emu-xref>) time zone name.</dd>
174+
</dl>
175+
176+
<p>
177+
This definition supersedes the definition provided in es2024, <emu-xref href="#sec-systemtimezoneidentifier"></emu-xref>.
178+
</p>
100179
</emu-clause>
101180

102-
<ins class="block">
103-
<emu-clause id="sup-availabletimezones" type="implementation-defined abstract operation">
104-
<h1>
105-
AvailableTimeZones (
106-
): a List of Strings
107-
</h1>
108-
<dl class="header">
109-
<dt>description</dt>
110-
<dd>The returned List is a sorted List of supported Zone and Link names in the IANA Time Zone Database.</dd>
111-
<dt>redefinition</dt>
112-
<dd>true</dd>
113-
</dl>
114-
<emu-alg>
115-
1. Let _timeZones_ be a List containing the String value of each Zone or Link name in the IANA Time Zone Database that is supported by the implementation.
116-
1. Assert: _timeZones_ contains *"UTC"*.
117-
1. Assert: _timeZones_ does not contain any element that does not identify a Zone or Link name in the IANA Time Zone Database.
118-
1. Return SortStringListByCodeUnit(_timeZones_).
119-
</emu-alg>
181+
<emu-clause id="sec-availabletimezones" type="implementation-defined abstract operation">
182+
<h1>
183+
AvailableTimeZones (
184+
): a List of Strings
185+
</h1>
186+
<dl class="header">
187+
<dt>description</dt>
188+
<dd>The returned List is a sorted List of supported Zone and Link names in the IANA Time Zone Database.</dd>
189+
</dl>
190+
<emu-alg>
191+
1. Let _timeZones_ be a List containing the String value of each Zone or Link name in the IANA Time Zone Database that is supported by the implementation.
192+
1. Assert: _timeZones_ contains *"UTC"*.
193+
1. Assert: _timeZones_ does not contain any element that does not identify a Zone or Link name in the IANA Time Zone Database.
194+
1. Return SortStringListByCodeUnit(_timeZones_).
195+
</emu-alg>
120196

121-
<p>This definition supersedes the definition provided in <emu-xref href="#sec-availabletimezones"></emu-xref>.</p>
122-
</emu-clause>
123-
</ins>
197+
<p>This definition supersedes the definition provided in [removed].</p>
198+
</emu-clause>
124199
</emu-clause>
200+
</del>
125201

126202
<emu-clause id="sec-abstract-operations">
127203
<h1><a href="https://tc39.es/ecma402/#sec-abstract-operations">Abstract Operations</a></h1>
@@ -244,13 +320,14 @@ <h1>InitializeDateTimeFormat ( _dateTimeFormat_, _locales_, _options_ [ , <ins>_
244320
1. <ins>If _toLocaleStringTimeZone_ is present, then</ins>
245321
1. <ins>Set _timeZone_ to _toLocaleStringTimeZone_.</ins>
246322
1. <ins>Else,</ins>
247-
1. Set _timeZone_ to DefaultTimeZone().
323+
1. Set _timeZone_ to SystemTimeZoneIdentifier().
248324
1. Else,
249325
1. <ins>If _toLocaleStringTimeZone_ is present, throw a *TypeError* exception.</ins>
250326
1. Set _timeZone_ to ? ToString(_timeZone_).
251-
1. If <del>the result of IsValidTimeZoneName(_timeZone_)</del><ins>IsAvailableTimeZoneName(_timeZone_)</ins> is *false*, then
327+
1. <ins>Let _timeZoneIdentifierRecord_ be GetAvailableNamedTimeZoneIdentifier(_timeZone_).</ins>
328+
1. If <del>the result of IsValidTimeZoneName(_timeZone_) is *false*</del><ins>_timeZoneIdentifierRecord_ is ~empty~</ins>, then
252329
1. Throw a *RangeError* exception.
253-
1. Set _timeZone_ to CanonicalizeTimeZoneName(_timeZone_).
330+
1. Set _timeZone_ to <del>CanonicalizeTimeZoneName(_timeZone_)</del><ins>_timeZoneIdentifierRecord_.[[PrimaryIdentifier]]</ins>.
254331
1. Set _dateTimeFormat_.[[TimeZone]] to _timeZone_.
255332
1. Let _formatOptions_ be a new Record.
256333
1. Set _formatOptions_.[[hourCycle]] to _hc_.
@@ -1275,7 +1352,8 @@ <h1>Intl.DateTimeFormat.prototype.resolvedOptions ( )</h1>
12751352
</p>
12761353

12771354
<emu-note>
1278-
In this version of the ECMAScript 2023 Internationalization API, the *"timeZone"* property will be the name of the default time zone if no *"timeZone"* property was provided in the options object provided to the Intl.DateTimeFormat constructor. The first edition left the *"timeZone"* property *undefined* in this case.
1355+
In this version of the ECMAScript Internationalization API, the *"timeZone"* property will be the name of the system time zone identifier if no *"timeZone"* property was provided in the options object provided to the Intl.DateTimeFormat constructor.
1356+
The first edition left the *"timeZone"* property *undefined* in this case.
12791357
</emu-note>
12801358

12811359
<emu-note>
@@ -2465,8 +2543,9 @@ <h1>Temporal.ZonedDateTime.prototype.toLocaleString ( [ _locales_ [ , _options_
24652543
1. Let _dateTimeFormat_ be ! OrdinaryCreateFromConstructor(%DateTimeFormat%, %DateTimeFormat.prototype%, « [[InitializedDateTimeFormat]], [[Locale]], [[Calendar]], [[NumberingSystem]], [[TimeZone]], [[Weekday]], [[Era]], [[Year]], [[Month]], [[Day]], [[DayPeriod]], [[Hour]], [[Minute]], [[Second]], [[FractionalSecondDigits]], [[TimeZoneName]], [[HourCycle]], [[Pattern]], [[BoundFormat]] »).
24662544
1. Let _timeZone_ be ? ToTemporalTimeZoneIdentifier(_zonedDateTime_.[[TimeZone]]).
24672545
1. If IsTimeZoneOffsetString(_timeZone_) is *true*, throw a *RangeError* exception.
2468-
1. If IsAvailableTimeZoneName(_timeZone_) is *false*, throw a *RangeError* exception.
2469-
1. Set _timeZone_ to CanonicalizeTimeZoneName(_timeZone_).
2546+
1. Let _timeZoneIdentifierRecord_ be GetAvailableNamedTimeZoneIdentifier(_timeZone_).
2547+
1. If _timeZoneIdentifierRecord_ is ~empty~, throw a *RangeError* exception.
2548+
1. Set _timeZone_ to _timeZoneIdentifierRecord_.[[PrimaryIdentifier]].
24702549
1. Perform ? InitializeDateTimeFormat(_dateTimeFormat_, _locales_, _options_, _timeZone_).
24712550
1. Let _calendar_ be ? ToTemporalCalendarIdentifier(_zonedDateTime_.[[Calendar]]).
24722551
1. If _calendar_ is not *"iso8601"* and not equal to _dateTimeFormat_.[[Calendar]], then

0 commit comments

Comments
 (0)