Skip to content

Commit 93bda94

Browse files
committed
Editorial: Refactor time zone identifier spec text
1 parent 844a887 commit 93bda94

File tree

3 files changed

+232
-103
lines changed

3 files changed

+232
-103
lines changed

spec/intl.html

Lines changed: 97 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -40,23 +40,76 @@ <h1><a href="https://tc39.es/ecma402/#sec-case-sensitivity-and-case-mapping">Cas
4040
</del>
4141
</emu-clause>
4242

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>
43+
<emu-clause id="sup-time-zone-support" oldids="sec-time-zone-names">
44+
<h1><a href="https://tc39.es/ecma402/#sec-time-zone-support">Time Zone Support</a></h1>
4545

4646
<ins class="block">
4747
<p>
48-
<emu-xref href="#sec-time-zone-names"></emu-xref> defines a set of abstract operations concerning the names of supported time zones.
48+
<emu-xref href="#sec-time-zone-support"></emu-xref> defines a set of abstract operations related to the identifiers of supported time zones.
4949
This section introduces additional requirements on these operations for implementations.
5050
</p>
51+
52+
<emu-clause id="sup-time-zone-identifiers">
53+
<h1>Time Zone Identifiers</h1>
54+
55+
<p>
56+
The ECMAScript Internationalization API Specification identifies time zones using the Zone and Link names of the IANA Time Zone Database <a href="https://www.iana.org/time-zones/">https://www.iana.org/time-zones/</a>.
57+
Time zone identifiers are case-insensitive and so are compared using ASCII case-insensitive comparisons, but time zone identifiers returned by ECMAScript built-in objects always use the casing found in the IANA Time Zone Database.
58+
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.
59+
In an implementation that implements the ECMAScript Internationalization API Specification, available named time zone identifiers are the set of Zone and Link identifiers that are supported by an ECMAScript implementation.
60+
</p>
61+
62+
<p>
63+
In the IANA Time Zone Database, the UTC time zone is represented by the Zone *"Etc/UTC"*, and is distinct from the Zone *"Etc/GMT"*.
64+
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 treatment of *"Etc/UTC"*, *"Etc/GMT"*, and *"GMT"* (if available) as non-primary identifiers that resolve to *"UTC"*.
65+
This is the only deviation from the IANA Time Zone Database that is required of an ECMAScript implementation.
66+
</p>
67+
68+
<p>
69+
Time zone aware ECMAScript implementations support *"UTC"* and all other Zone and Link names (and <b>only</b> such names) from the IANA Time Zone Database, the mapping between Link names and corresponding Zone names, and the UTC offsets and transitions associated with Zone names that represent local political rules for that time zone.
70+
An ECMAScript implementation that includes the ECMA-402 Internationalization API <b>must</b> be time zone aware.
71+
Some implementations that do not implement the ECMA-402 Internationalization API may also be time zone aware.
72+
</p>
73+
74+
<p>
75+
The IANA Time Zone Database is typically updated between five and ten times per year, so it is recommended to use the best available current and historical time zone information.
76+
This information includes which identifiers are supported, the primary time zone identifier associated with any identifier, and the UTC offsets and transitions associated with any Zone.
77+
</p>
78+
79+
<p>
80+
New Zone identifiers can be added to the IANA Time Zone Database, for example when one part of a country starts observing Daylight Saving Time differently from other parts, or when a new country declares independence.
81+
ECMAScript implementations are recommended to include newly-added identifiers as soon as possible into the results of AvailableNamedTimeZoneIdentifiers.
82+
Such prompt action ensures that ECMAScript programs receiving those identifiers from an external source (including the host's operating system) will be able to recognize and calculate using the new time zone.
83+
</p>
84+
85+
<p>
86+
It is recommended that implementations maintain a fully consistent copy of the IANA Time Zone Database for the lifetime of each agent.
87+
If implementations do revise time zone information during the lifetime of an agent, then it is recommended that changes to time zone data, including which identifiers are supported, the primary time zone identifier associated with any identifier, and the UTC offsets and transitions associated with any Zone, can be incorporated into an agent only if they are consistent with results already observed by all ECMAScript code that can reach that agent.
88+
For example, it is recommended that a new identifier can be incorporated only if no ECMAScript code has already tried to use it, and it is recommended that replacement of a primary identifier with a Link to a different identifier can only be incorporated only if no ECMAScript code has already resulted in resolving it as primary.
89+
Due to the complexity of supporting these recommendations, it is recommended that implementations maintain a fully consistent copy of the IANA Time Zone Database for the lifetime of each agent.
90+
</p>
91+
92+
<emu-note>
93+
<p>
94+
The IANA Time Zone Database offers build options that affect which time zone identifiers are primary.
95+
It is recommended that ECMAScript implementations <b>should not</b> determine which identifiers are primary and non-primary using the data generated by the default build options of the IANA Time Zone Database, because those default build options merge geographically unrelated time zones together, such as *"Atlantic/Reykjavik"* as a Link to the Zone *"Africa/Abidjan"*.
96+
These merges can be problematic because geographically and politically distinct locations, especially across country boundaries, are more likely to introduce divergent time zone rules in a future version of the IANA Time Zone Database.
97+
Therefore, it is recommended that all identifiers listed in the IANA Time Zone Database's <code>zone.tab</code> file (which lists at least one Link or Zone name for each <a href="https://www.iso.org/glossary-for-iso-3166.html">ISO 3166-1 Alpha-2</a> country code in the IANA Time Zone Database) should be primary identifiers.
98+
One way to achieve this result is to build the IANA Time Zone Database with the <code>PACKRATDATA=backzone PACKRATLIST=zone.tab</code> build options.
99+
</p>
100+
</emu-note>
101+
</emu-clause>
51102
</ins>
52103

104+
<del class="block">
53105
<p>
54106
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.
55107
</p>
56108

57109
<p>
58-
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.
110+
A conforming implementation must recognize *"UTC"* and all other Zone and Link names (and <b>only</b> 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.
59111
</p>
112+
</del>
60113

61114
<del class="block">
62115
<emu-clause id="sup-isvalidtimezonename">
@@ -74,10 +127,11 @@ <h1><a href="https://tc39.es/ecma402/#sec-isvalidtimezonename">IsValidTimeZoneNa
74127
</emu-clause>
75128
</del>
76129

130+
<del class="block">
77131
<emu-clause id="sup-canonicalizetimezonename" type="abstract operation">
78132
<h1>
79133
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>,
134+
_timeZone_: a String value that is a valid time zone name as verified by IsValidTimeZoneName,
81135
)
82136
</h1>
83137
<dl class="header">
@@ -93,32 +147,46 @@ <h1>
93147
1. If _ianaTimeZone_ is *"Etc/UTC"* or *"Etc/GMT"*, return *"UTC"*.
94148
1. Return _ianaTimeZone_.
95149
</emu-alg>
96-
97-
<ins class="block">
98-
<p>This definition supersedes the definition provided in <emu-xref href="#sec-canonicalizetimezonename"></emu-xref>.</p>
99-
</ins>
100150
</emu-clause>
151+
</del>
101152

102153
<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>
154+
<emu-clause id="sup-availablenamedtimezoneidentifiers" oldids="sec-availabletimezones" type="implementation-defined abstract operation">
155+
<h1>AvailableNamedTimeZoneIdentifiers ( ): a List of Time Zone Identifier Records</h1>
108156
<dl class="header">
109157
<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>
158+
<dd>
159+
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.
160+
The List is sorted by [[Identifier]] of each Time Zone Identifier Record.
161+
</dd>
111162
<dt>redefinition</dt>
112163
<dd>true</dd>
113164
</dl>
114165
<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_).
166+
1. Let _identifiers_ 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.
167+
1. Assert: No element of _identifiers_ is an ASCII-case-insensitive match for any other element.
168+
1. Assert: Every element of _identifiers_ identifies a Zone or Link name in the IANA Time Zone Database.
169+
1. Set _identifiers_ to SortStringListByCodeUnit(_identifiers_).
170+
1. Let _result_ be a new empty List.
171+
1. For each element _identifier_ of _identifiers_, do
172+
1. Let _primary_ be _identifier_.
173+
1. If _identifier_ is a non-primary time zone identifier and _identifier_ is not *"UTC"*, then
174+
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.
175+
1. NOTE: If _identifier_ resolves to another non-primary time zone identifier, then the implementation must continue resolution of the entire chain until its terminal primary time zone identifier.
176+
1. If _primary_ is one of *"Etc/UTC"*, *"Etc/GMT"*, or *"GMT"*, set _primary_ to *"UTC"*.
177+
1. Let _record_ be the Time Zone Identifier Record { [[Identifier]]: _identifier_, [[PrimaryIdentifier]]: _primary_ }.
178+
1. Append _record_ to the end of _result_.
179+
1. Assert: One element of _result_ is the Time Zone Identifier Record { [[Identifier]]: *"UTC"*, [[PrimaryIdentifier]]: *"UTC"* }.
180+
1. Return _result_.
119181
</emu-alg>
120182

121-
<p>This definition supersedes the definition provided in <emu-xref href="#sec-availabletimezones"></emu-xref>.</p>
183+
<emu-note>
184+
Time zone identifiers in the IANA Time Zone Database can change over time.
185+
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.
186+
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.
187+
</emu-note>
188+
189+
<p>This definition supersedes the definition provided in <emu-xref href="#sec-availablenamedtimezoneidentifiers"></emu-xref>.</p>
122190
</emu-clause>
123191
</ins>
124192
</emu-clause>
@@ -244,13 +312,14 @@ <h1>InitializeDateTimeFormat ( _dateTimeFormat_, _locales_, _options_ [ , <ins>_
244312
1. <ins>If _toLocaleStringTimeZone_ is present, then</ins>
245313
1. <ins>Set _timeZone_ to _toLocaleStringTimeZone_.</ins>
246314
1. <ins>Else,</ins>
247-
1. Set _timeZone_ to DefaultTimeZone().
315+
1. Set _timeZone_ to SystemTimeZoneIdentifier().
248316
1. Else,
249317
1. <ins>If _toLocaleStringTimeZone_ is present, throw a *TypeError* exception.</ins>
250318
1. Set _timeZone_ to ? ToString(_timeZone_).
251-
1. If <del>the result of IsValidTimeZoneName(_timeZone_)</del><ins>IsAvailableTimeZoneName(_timeZone_)</ins> is *false*, then
319+
1. <ins>Let _timeZoneIdentifierRecord_ be GetAvailableNamedTimeZoneIdentifier(_timeZone_).</ins>
320+
1. If <del>the result of IsValidTimeZoneName(_timeZone_) is *false*</del><ins>_timeZoneIdentifierRecord_ is ~empty~</ins>, then
252321
1. Throw a *RangeError* exception.
253-
1. Set _timeZone_ to CanonicalizeTimeZoneName(_timeZone_).
322+
1. Set _timeZone_ to <del>CanonicalizeTimeZoneName(_timeZone_)</del><ins>_timeZoneIdentifierRecord_.[[PrimaryIdentifier]]</ins>.
254323
1. Set _dateTimeFormat_.[[TimeZone]] to _timeZone_.
255324
1. Let _formatOptions_ be a new Record.
256325
1. Set _formatOptions_.[[hourCycle]] to _hc_.
@@ -1274,7 +1343,8 @@ <h1>Intl.DateTimeFormat.prototype.resolvedOptions ( )</h1>
12741343
</p>
12751344

12761345
<emu-note>
1277-
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.
1346+
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.
1347+
The first edition left the *"timeZone"* property *undefined* in this case.
12781348
</emu-note>
12791349

12801350
<emu-note>
@@ -2468,8 +2538,9 @@ <h1>Temporal.ZonedDateTime.prototype.toLocaleString ( [ _locales_ [ , _options_
24682538
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]] »).
24692539
1. Let _timeZone_ be ? ToTemporalTimeZoneIdentifier(_zonedDateTime_.[[TimeZone]]).
24702540
1. If IsTimeZoneOffsetString(_timeZone_) is *true*, throw a *RangeError* exception.
2471-
1. If IsAvailableTimeZoneName(_timeZone_) is *false*, throw a *RangeError* exception.
2472-
1. Set _timeZone_ to CanonicalizeTimeZoneName(_timeZone_).
2541+
1. Let _timeZoneIdentifierRecord_ be GetAvailableNamedTimeZoneIdentifier(_timeZone_).
2542+
1. If _timeZoneIdentifierRecord_ is ~empty~, throw a RangeError exception.
2543+
1. Set _timeZone_ to _timeZoneIdentifierRecord_.[[PrimaryIdentifier]].
24732544
1. Perform ? InitializeDateTimeFormat(_dateTimeFormat_, _locales_, _options_, _timeZone_).
24742545
1. Let _calendar_ be ? ToTemporalCalendarIdentifier(_zonedDateTime_.[[Calendar]]).
24752546
1. If _calendar_ is not *"iso8601"* and not equal to _dateTimeFormat_.[[Calendar]], then

spec/temporal.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ <h1>Temporal.Now.timeZoneId ( )</h1>
9797
This function performs the following steps when called:
9898
</p>
9999
<emu-alg>
100-
1. Return DefaultTimeZone().
100+
1. Return SystemTimeZoneIdentifier().
101101
</emu-alg>
102102
</emu-clause>
103103

@@ -240,7 +240,7 @@ <h1>SystemInstant ( )</h1>
240240
<h1>SystemDateTime ( _temporalTimeZoneLike_, _calendarLike_ )</h1>
241241
<emu-alg>
242242
1. If _temporalTimeZoneLike_ is *undefined*, then
243-
1. Let _timeZone_ be DefaultTimeZone().
243+
1. Let _timeZone_ be SystemTimeZoneIdentifier().
244244
1. Else,
245245
1. Let _timeZone_ be ? ToTemporalTimeZoneSlotValue(_temporalTimeZoneLike_).
246246
1. Let _calendar_ be ? ToTemporalCalendarSlotValue(_calendarLike_).
@@ -253,7 +253,7 @@ <h1>SystemDateTime ( _temporalTimeZoneLike_, _calendarLike_ )</h1>
253253
<h1>SystemZonedDateTime ( _temporalTimeZoneLike_, _calendarLike_ )</h1>
254254
<emu-alg>
255255
1. If _temporalTimeZoneLike_ is *undefined*, then
256-
1. Let _timeZone_ be DefaultTimeZone().
256+
1. Let _timeZone_ be SystemTimeZoneIdentifier().
257257
1. Else,
258258
1. Let _timeZone_ be ? ToTemporalTimeZoneSlotValue(_temporalTimeZoneLike_).
259259
1. Let _calendar_ be ? ToTemporalCalendarSlotValue(_calendarLike_).

0 commit comments

Comments
 (0)