You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Editorial: refactor time zone identifier spec text
This commit simplifies and clarifies spec text related to time zone
identifiers. Goals include making it easier to integrate Temporal
into ECMA-262 soon, and simplifying both Temporal and ECMA-402
spec text by centralizing common logic in ECMA-262.
If this commit is merged into ECMA-262, editorial PRs will follow for
Temporal (draft: tc39/proposal-temporal#2573)
and ECMA-402 (draft TBD) to leverage the updated spec text and
AOs to simplify those specs.
Changes:
* Adds editorial spec text explaining how time zone identifiers work in
ECMAScript, and pointing readers to 402 for implementations that use
the IANA TimeZoneDatabase.
* Adds definitions related to time zone identifiers.
* Renames `DefaultTimeZone` to `SystemTimeZoneIdentifier` in order
to more clearly match its intent.
* Removes the need to override `SystemTimeZoneIdentifier` in ECMA-402.
* Renames variables named _timeZone_ to _timeZoneIdentifier_
to avoid future ambiguity with `Temporal.TimeZone`.
* Adds text that more clearly explains existing spec text allowing
non-402 implementations to support non-UTC time zones.
* Adds new abstract operation `AvailableNamedTimeZoneIdentifiers`
which, along with the existing (renamed) `SystemTimeZoneIdentifier`,
enables all ECMA-402 and Temporal operations related to time zone
identifiers to be implemented on top of these AOs.
Time zones in ECMAScript are described using <dfn variants="time zone identifier">time zone identifiers</dfn>, which must be Strings composed entirely of characters from the Unicode Basic Latin block.
32151
+
Time zone identifiers are case-insensitive and so are compared using ASCII case-insensitive comparisons.
32152
+
Built-in time zones may be <dfn variants="named time zone">named time zones</dfn>, represented by the [[Identifier]] property of the records returned by AvailableTimeZoneIdentifiers.
32153
+
They may also be <dfn variants="offset time zone">offset time zones</dfn>, represented by Strings for which IsTimeZoneOffsetString returns *true*.
32154
+
</p>
32155
+
<p>
32156
+
A <dfn variants="primary time zone identifiers">primary time zone identifier</dfn> represents the preferred identifier of a named time zone, while a <dfn variants="non-primary time zone identifiers">non-primary time zone identifier</dfn> is an alternate identifier for the same named time zone.
32157
+
The set of built-in, named time zone identifiers (both primary and non-primary) that are supported by an ECMAScript implementation are called available time zone identifiers.
32158
+
</p>
32159
+
<p>
32160
+
At a minimum, ECMAScript implementations must support a built-in time zone with the identifier *"UTC"*, which must be primary.
32161
+
If the return value _tz_ of SystemTimeZoneIdentifier is different from *"UTC"*, and IsTimeZoneOffsetString(_tz_) is *false*, then implementations must also support _tz_ as a built-in time zone identifier, and it must be primary as well.
32162
+
In addition, implementations may support any number of other built-in time zones.
32163
+
</p>
32164
+
<p>
32165
+
Implementations that follow the requirements for time zones as described in the ECMA-402 Internationalization API specification are called <dfn>time zone aware</dfn>.
32166
+
Time zone aware implementations must define built-in named time zones corresponding to the Zone and Link names of the IANA Time Zone Database (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 as specified in the ECMA-402 specification.
32167
+
An ECMAScript implementation that includes the ECMA-402 Internationalization API <b>must</b> be time zone aware.
32168
+
However, it is recommended that all ECMAScript implementations be time zone aware, including those that do not implement the ECMA-402 Internationalization API.
32169
+
Furthermore, even non-time zone aware 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>It is recommended that implementations use the time zone information of the IANA Time Zone Database <a href="https://www.iana.org/time-zones/">https://www.iana.org/time-zones/</a>.</p>
32206
+
<p>It is required for time zone aware implementations (and recommended for all others) to use the time zone information of the IANA Time Zone Database <a href="https://www.iana.org/time-zones/">https://www.iana.org/time-zones/</a>.</p>
32180
32207
<p>1:30 AM on 5 November 2017 in America/New_York is repeated twice, so GetNamedTimeZoneEpochNanoseconds(*"America/New_York"*, 2017, 11, 5, 1, 30, 0, 0, 0, 0) would return a List of length 2 in which the first element represents 05:30 UTC (corresponding with 01:30 US Eastern Daylight Time at UTC offset -04:00) and the second element represents 06:30 UTC (corresponding with 01:30 US Eastern Standard Time at UTC offset -05:00).</p>
32181
32208
<p>2:30 AM on 12 March 2017 in America/New_York does not exist, so GetNamedTimeZoneEpochNanoseconds(*"America/New_York"*, 2017, 3, 12, 2, 30, 0, 0, 0, 0) would return an empty List.</p>
<p>A <dfn variants="Time Zone Identifier Records">Time Zone Identifier Record</dfn> is a Record used to describe an available time zone identifier, as well as the primary time zone identifier corresponding to it.</p>
32235
+
<p>Time Zone Identifier Records have the fields listed in <emu-xref href="#table-time-zone-identifier-record-fields"></emu-xref>.</p>
32236
+
<emu-table id="table-time-zone-identifier-record-fields" caption="Time Zone Identifier Record Fields">
32237
+
<table>
32238
+
<tr>
32239
+
<th>Field Name</th>
32240
+
<th>Value</th>
32241
+
<th>Meaning</th>
32242
+
</tr>
32243
+
<tr>
32244
+
<td>[[Identifier]]</td>
32245
+
<td>a String</td>
32246
+
<td>An available time zone identifier that is supported by the implementation.</td>
32247
+
</tr>
32248
+
<tr>
32249
+
<td>[[PrimaryIdentifier]]</td>
32250
+
<td>a String</td>
32251
+
<td>The primary time zone identifier that [[Identifier]] resolves to.</td>
32252
+
</tr>
32253
+
</table>
32254
+
</emu-table>
32255
+
<emu-note>
32256
+
<p>If [[Identifier]] is a primary time zone identifier, then [[Identifier]] will be [[PrimaryIdentifier]].</p>
<h1>AvailableTimeZoneIdentifiers ( ): a List of Time Zone Identifier Records</h1>
32207
32262
<dl class="header">
32208
32263
<dt>description</dt>
32209
-
<dd>It returns a String value representing the host environment's current time zone, which is either a String representing a UTC offset for which IsTimeZoneOffsetString returns *true*, or a String identifier accepted by GetNamedTimeZoneEpochNanoseconds and GetNamedTimeZoneOffsetNanoseconds.</dd>
32264
+
<dd>
32265
+
Its result describes all available time zone identifiers in this implementation, as well as the primary time zone identifier corresponding to each available identifier.
32266
+
The List is sorted by [[Identifier]] of each Time Zone Identifier Record.
32267
+
</dd>
32210
32268
</dl>
32269
+
<p>
32270
+
Time zone aware implementations, including all implementations that implement the ECMA-402 Internationalization API, must implement the AvailableTimeZoneIdentifiers abstract operation as specified in the ECMA-402 specification.
32271
+
For implementations that are not time zone aware, the following specification is used.
32272
+
</p>
32273
+
<emu-alg>
32274
+
1. If the implementation does not include local political rules for any time zones, then
32275
+
1. Return a new List containing only one element: the Time Zone Identifier Record { [[Identifier]]: *"UTC"*, [[PrimaryIdentifier]]: *"UTC"* }.
32276
+
1. Let _identifiers_ be the List of String values representing time zones supported by the implementation.
32277
+
1. [declared="comparefn"] Sort _identifiers_ into the same order as if an Array of the same values had been sorted using %Array.prototype.sort% with *undefined* as _comparefn_.
32278
+
1. Let _result_ be a new empty List.
32279
+
1. For each element _identifier_ of _identifiers_, do
32280
+
1. Let _primary_ be _identifier_.
32281
+
1. If _identifier_ is a non-primary time zone identifier in this implementation and _identifier_ is not *"UTC"*, then
32282
+
1. Set _primary_ to the name of the primary time zone identifier that _identifier_ resolves to in this implementation.
32283
+
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.
32284
+
1. Let _record_ be the Time Zone Identifier Record { [[Identifier]]: _identifier_, [[PrimaryIdentifier]]: _primary_ }.
32285
+
1. Append _record_ to the end of _result_.
32286
+
1. Assert: One element of _result_ is the Time Zone Identifier Record { [[Identifier]]: *"UTC"*, [[PrimaryIdentifier]]: *"UTC"* }.
32287
+
1. Return _result_.
32288
+
</emu-alg>
32289
+
</emu-clause>
32211
32290
32212
-
<p>An ECMAScript implementation that includes the ECMA-402 Internationalization API must implement the DefaultTimeZone abstract operation as specified in the ECMA-402 specification.</p>
32213
-
<p>The default implementation of DefaultTimeZone, to be used for ECMAScript implementations that do not include local political rules for any time zones, performs the following steps when called:</p>
It returns a String value representing the environment's current time zone, which is either a String representing a UTC offset for which IsTimeZoneOffsetString returns *true*, or a primary time zone identifier.
32297
+
</dd>
32298
+
</dl>
32214
32299
32215
32300
<emu-alg>
32216
-
1. Return *"UTC"*.
32301
+
1. If the implementation only supports the UTC time zone, return *"UTC"*.
32302
+
1. Let _systemTimeZoneString_ be the String representing the host environment's current time zone, either a time zone identifier or a UTC offset string.
32303
+
1. If IsTimeZoneOffsetString(_systemTimeZoneString_) is *true*, return _systemTimeZoneString_.
32304
+
1. Assert: _systemTimeZoneString_ is equal to the [[PrimaryIdentifier]] property of at least one Time Zone Identifier Record returned by AvailableTimeZoneIdentifiers().
32305
+
1. Return _systemTimeZoneString_.
32217
32306
</emu-alg>
32218
32307
32219
32308
<emu-note>
32220
32309
<p>
32221
-
To ensure the level of functionality that implementations commonly provide in the methods of the Date object, it is recommended that DefaultTimeZone return an IANA time zone name corresponding to the host environment's time zone setting, if such a thing exists.
32310
+
To ensure the level of functionality that implementations commonly provide in the methods of the Date object, it is recommended that SystemTimeZoneIdentifier return an IANA time zone name corresponding to the host environment's time zone setting, if such a thing exists.
32222
32311
GetNamedTimeZoneEpochNanoseconds and GetNamedTimeZoneOffsetNanoseconds must reflect the local political rules for standard time and daylight saving time in that time zone, if such rules exist.
32223
32312
</p>
32224
-
<p>For example, if the host environment is a browser on a system where the user has chosen US Eastern Time as their time zone, DefaultTimeZone returns *"America/New_York"*.</p>
32313
+
<p>For example, if the host environment is a browser on a system where the user has chosen US Eastern Time as their time zone, SystemTimeZoneIdentifier returns *"America/New_York"*.</p>
32225
32314
</emu-note>
32226
32315
</emu-clause>
32227
32316
@@ -32239,17 +32328,17 @@ <h1>
32239
32328
</dd>
32240
32329
</dl>
32241
32330
<emu-alg>
32242
-
1. Let _localTimeZone_ be DefaultTimeZone().
32243
-
1. If IsTimeZoneOffsetString(_localTimeZone_) is *true*, then
32244
-
1. Let _offsetNs_ be ParseTimeZoneOffsetString(_localTimeZone_).
32331
+
1. Let _systemTimeZoneIdentifier_ be SystemTimeZoneIdentifier().
32332
+
1. If IsTimeZoneOffsetString(_systemTimeZoneIdentifier_) is *true*, then
32333
+
1. Let _offsetNs_ be ParseTimeZoneOffsetString(_systemTimeZoneIdentifier_).
32245
32334
1. Else,
32246
-
1. Let _offsetNs_ be GetNamedTimeZoneOffsetNanoseconds(_localTimeZone_, ā¤(ā(_t_) Ć 10<sup>6</sup>)).
32335
+
1. Let _offsetNs_ be GetNamedTimeZoneOffsetNanoseconds(_systemTimeZoneIdentifier_, ā¤(ā(_t_) Ć 10<sup>6</sup>)).
32247
32336
1. Let _offsetMs_ be truncate(_offsetNs_ / 10<sup>6</sup>).
32248
32337
1. Return _t_ + š½(_offsetMs_).
32249
32338
</emu-alg>
32250
-
<p>If political rules for the local time _t_ are not available within the implementation, the result is _t_ because DefaultTimeZone returns *"UTC"* and GetNamedTimeZoneOffsetNanoseconds returns 0.</p>
32339
+
<p>If political rules for the local time _t_ are not available within the implementation, the result is _t_ because SystemTimeZoneIdentifier returns *"UTC"* and GetNamedTimeZoneOffsetNanoseconds returns 0.</p>
32251
32340
<emu-note>
32252
-
<p>It is recommended that implementations use the time zone information of the IANA Time Zone Database <a href="https://www.iana.org/time-zones/">https://www.iana.org/time-zones/</a>.</p>
32341
+
<p>It is required for time zone aware implementations (and recommended for all others) to use the time zone information of the IANA Time Zone Database <a href="https://www.iana.org/time-zones/">https://www.iana.org/time-zones/</a>.</p>
32253
32342
</emu-note>
32254
32343
<emu-note>
32255
32344
<p>Two different input time values <emu-eqn>_t_<sub>UTC</sub></emu-eqn> are converted to the same local time <emu-eqn>t<sub>local</sub></emu-eqn> at a negative time zone transition when there are repeated times (e.g. the daylight saving time ends or the time zone adjustment is decreased.).</p>
@@ -32271,19 +32360,19 @@ <h1>
32271
32360
</dd>
32272
32361
</dl>
32273
32362
<emu-alg>
32274
-
1. Let _localTimeZone_ be DefaultTimeZone().
32275
-
1. If IsTimeZoneOffsetString(_localTimeZone_) is *true*, then
32276
-
1. Let _offsetNs_ be ParseTimeZoneOffsetString(_localTimeZone_).
32363
+
1. Let _systemTimeZoneIdentifier_ be SystemTimeZoneIdentifier().
32364
+
1. If IsTimeZoneOffsetString(_systemTimeZoneIdentifier_) is *true*, then
32365
+
1. Let _offsetNs_ be ParseTimeZoneOffsetString(_systemTimeZoneIdentifier_).
32277
32366
1. Else,
32278
-
1. Let _possibleInstants_ be GetNamedTimeZoneEpochNanoseconds(_localTimeZone_, ā(YearFromTime(_t_)), ā(MonthFromTime(_t_)) + 1, ā(DateFromTime(_t_)), ā(HourFromTime(_t_)), ā(MinFromTime(_t_)), ā(SecFromTime(_t_)), ā(msFromTime(_t_)), 0, 0).
32367
+
1. Let _possibleInstants_ be GetNamedTimeZoneEpochNanoseconds(_systemTimeZoneIdentifier_, ā(YearFromTime(_t_)), ā(MonthFromTime(_t_)) + 1, ā(DateFromTime(_t_)), ā(HourFromTime(_t_)), ā(MinFromTime(_t_)), ā(SecFromTime(_t_)), ā(msFromTime(_t_)), 0, 0).
32279
32368
1. NOTE: The following steps ensure that when _t_ represents local time repeating multiple times at a negative time zone transition (e.g. when the daylight saving time ends or the time zone offset is decreased due to a time zone rule change) or skipped local time at a positive time zone transition (e.g. when the daylight saving time starts or the time zone offset is increased due to a time zone rule change), _t_ is interpreted using the time zone offset before the transition.
32280
32369
1. If _possibleInstants_ is not empty, then
32281
32370
1. Let _disambiguatedInstant_ be _possibleInstants_[0].
32282
32371
1. Else,
32283
32372
1. NOTE: _t_ represents a local time skipped at a positive time zone transition (e.g. due to daylight saving time starting or a time zone rule change increasing the UTC offset).
32284
-
1. [declared="tBefore"] Let _possibleInstantsBefore_ be GetNamedTimeZoneEpochNanoseconds(_localTimeZone_, ā(YearFromTime(_tBefore_)), ā(MonthFromTime(_tBefore_)) + 1, ā(DateFromTime(_tBefore_)), ā(HourFromTime(_tBefore_)), ā(MinFromTime(_tBefore_)), ā(SecFromTime(_tBefore_)), ā(msFromTime(_tBefore_)), 0, 0), where _tBefore_ is the largest integral Number < _t_ for which _possibleInstantsBefore_ is not empty (i.e., _tBefore_ represents the last local time before the transition).
32373
+
1. [declared="tBefore"] Let _possibleInstantsBefore_ be GetNamedTimeZoneEpochNanoseconds(_systemTimeZoneIdentifier_, ā(YearFromTime(_tBefore_)), ā(MonthFromTime(_tBefore_)) + 1, ā(DateFromTime(_tBefore_)), ā(HourFromTime(_tBefore_)), ā(MinFromTime(_tBefore_)), ā(SecFromTime(_tBefore_)), ā(msFromTime(_tBefore_)), 0, 0), where _tBefore_ is the largest integral Number < _t_ for which _possibleInstantsBefore_ is not empty (i.e., _tBefore_ represents the last local time before the transition).
32285
32374
1. Let _disambiguatedInstant_ be the last element of _possibleInstantsBefore_.
32286
-
1. Let _offsetNs_ be GetNamedTimeZoneOffsetNanoseconds(_localTimeZone_, _disambiguatedInstant_).
32375
+
1. Let _offsetNs_ be GetNamedTimeZoneOffsetNanoseconds(_systemTimeZoneIdentifier_, _disambiguatedInstant_).
32287
32376
1. Let _offsetMs_ be truncate(_offsetNs_ / 10<sup>6</sup>).
32288
32377
1. Return _t_ - š½(_offsetMs_).
32289
32378
</emu-alg>
@@ -32293,9 +32382,9 @@ <h1>
32293
32382
For example, the maximum time value is 8.64 Ć 10<sup>15</sup>, corresponding with *"+275760-09-13T00:00:00Z"*.
32294
32383
In an environment where the local time zone offset is ahead of UTC by 1 hour at that instant, it is represented by the larger input of 8.64 Ć 10<sup>15</sup> + 3.6 Ć 10<sup>6</sup>, corresponding with *"+275760-09-13T01:00:00+01:00"*.
32295
32384
</p>
32296
-
<p>If political rules for the local time _t_ are not available within the implementation, the result is _t_ because DefaultTimeZone returns *"UTC"* and GetNamedTimeZoneOffsetNanoseconds returns 0.</p>
32385
+
<p>If political rules for the local time _t_ are not available within the implementation, the result is _t_ because SystemTimeZoneIdentifier returns *"UTC"* and GetNamedTimeZoneOffsetNanoseconds returns 0.</p>
32297
32386
<emu-note>
32298
-
<p>It is recommended that implementations use the time zone information of the IANA Time Zone Database <a href="https://www.iana.org/time-zones/">https://www.iana.org/time-zones/</a>.</p>
32387
+
<p>It is required for time zone aware implementations (and recommended for all others) to use the time zone information of the IANA Time Zone Database <a href="https://www.iana.org/time-zones/">https://www.iana.org/time-zones/</a>.</p>
32299
32388
<p>
32300
32389
1:30 AM on 5 November 2017 in America/New_York is repeated twice (fall backward), but it must be interpreted as 1:30 AM UTC-04 instead of 1:30 AM UTC-05.
32301
32390
In UTC(TimeClip(MakeDate(MakeDay(2017, 10, 5), MakeTime(1, 30, 0, 0)))), the value of _offsetMs_ is <emu-eqn>-4 Ć msPerHour</emu-eqn>.
@@ -33625,11 +33714,11 @@ <h1>
33625
33714
<dl class="header">
33626
33715
</dl>
33627
33716
<emu-alg>
33628
-
1. Let _localTimeZone_ be DefaultTimeZone().
33629
-
1. If IsTimeZoneOffsetString(_localTimeZone_) is *true*, then
33630
-
1. Let _offsetNs_ be ParseTimeZoneOffsetString(_localTimeZone_).
33717
+
1. Let _systemTimeZoneIdentifier_ be SystemTimeZoneIdentifier().
33718
+
1. If IsTimeZoneOffsetString(_systemTimeZoneIdentifier_) is *true*, then
33719
+
1. Let _offsetNs_ be ParseTimeZoneOffsetString(_systemTimeZoneIdentifier_).
33631
33720
1. Else,
33632
-
1. Let _offsetNs_ be GetNamedTimeZoneOffsetNanoseconds(_localTimeZone_, ā¤(ā(_tv_) Ć 10<sup>6</sup>)).
33721
+
1. Let _offsetNs_ be GetNamedTimeZoneOffsetNanoseconds(_systemTimeZoneIdentifier_, ā¤(ā(_tv_) Ć 10<sup>6</sup>)).
33633
33722
1. Let _offset_ be š½(truncate(_offsetNs_ / 10<sup>6</sup>)).
33634
33723
1. If _offset_ is *+0*<sub>š½</sub> or _offset_ > *+0*<sub>š½</sub>, then
0 commit comments