From 70a45763a04615420b4e2875ced6593ddf763344 Mon Sep 17 00:00:00 2001 From: Justin Grant Date: Sat, 30 Mar 2024 21:16:10 -0700 Subject: [PATCH] Normative: Update time zone ID requirements This PR resolves #825 by adding spec text that defines how ECMA-402 implementations should decide which IANA time zone IDs should be primary or non-primary. This PR implements "Option C" in #825 by deterministically defining ECMAScript's exceptions from the IANA Time Zone Database's defaults, and then pointing implementers at ICU as a convenient implementation of those exceptions. This PR also accommodates to web reality by aligning the 402 spec text with the existing behavior of ICU4C which is used by most (all?) major ECMAScript engines to implement time zone features. This PR is stacked on top of an editorial PR to align ECMA-402's time-zone-related spec text with ECMA-262. --- spec/locales-currencies-tz.html | 210 ++++++++++++++++++++++++++------ 1 file changed, 174 insertions(+), 36 deletions(-) diff --git a/spec/locales-currencies-tz.html b/spec/locales-currencies-tz.html index 55b6ade0..b09cc188 100644 --- a/spec/locales-currencies-tz.html +++ b/spec/locales-currencies-tz.html @@ -168,43 +168,134 @@

Use of the IANA Time Zone Database

- Implementations that adopt this specification must be time zone aware: they must use the IANA Time Zone Database https://www.iana.org/time-zones/ to supply time zone identifiers and data used in ECMAScript calculations and formatting. + Implementations of this specification must be time zone aware: they must use the IANA Time Zone Database https://www.iana.org/time-zones/ to supply time zone identifiers and data used in ECMAScript calculations and formatting. This section defines how the IANA Time Zone Database should be used by time zone aware implementations. -

-

- 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. - 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. + 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, or is *"Etc/Unknown"*. Available named time zone identifiers returned by ECMAScript built-in objects must use the casing found in the IANA Time Zone Database.

- 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"*. - 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"*. - This is the only deviation from the IANA Time Zone Database that is required of a time zone aware ECMAScript implementation. -

-

- The IANA Time Zone Database is typically updated between five and ten times per year. - 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. - ECMAScript implementations are recommended to include updates to the IANA Time Zone Database as soon as possible. - 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. + 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 that resolves to its corresponding Zone name, with the following exceptions implemented in AvailableNamedTimeZoneIdentifiers:

+ + + + Legacy POSIX Time Zone Identifier Mapping + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Legacy POSIX Zone NamePrimary Time Zone Identifier
*"EST"**"Etc/GMT+5"*
*"MST"**"Etc/GMT+7"*
*"HST"**"Etc/GMT+10"*
*"EST5EDT"**"America/New_York"*
*"CST6CDT"**"America/Chicago"*
*"MST7MDT"**"America/Denver"*
*"PST8PDT"**"America/Los_Angeles"*
*"WET"**"Europe/Lisbon"*
*"CET"**"Europe/Berlin"*
*"MET"**"Europe/Vienna"*
*"EET"**"Europe/Athens"*
+

- Although the IANA Time Zone Database maintainers strive for stability, in rare cases (averaging less than once per year) a Zone may be replaced by a new Zone. - For example, in 2022 "*Europe/Kiev*" was deprecated to a Link resolving to a new "*Europe/Kyiv*" Zone. -

-

- To reduce disruption from renaming changes, ECMAScript implementations are encouraged to initially add the new Zone as a non-primary time zone identifier that resolves to the current primary identifier. - Then, after a waiting period, implementations are recommended to promote the new Zone to a primary time zone identifier while simultaneously demoting the deprecated name to non-primary. - The recommended waiting period is two years after the IANA Time Zone Database release containing the changes. - This delay allows other systems, that ECMAScript programs may interact with, to be updated to recognize the new Zone. + The IANA Time Zone Database offers build options that affect which time zone identifiers are primary. + The default build options merge different countries' time zones, for example *"Atlantic/Reykjavik"* is built as a Link to the Zone *"Africa/Abidjan"*. + Geographically and politically distinct locations are likely to introduce divergent time zone rules in a future version of the IANA Time Zone Database. + The exceptions above serve to mitigate these future-compatibility issues for ECMAScript programmers and end users.

- A waiting period should only apply when a new Zone is added to replace an existing Zone. - If an existing Zone and Link are swapped, then no waiting period is necessary. + International Components for Unicode (ICU) https://icu.unicode.org/ is a widely-used library that exposes IANA Time Zone Database information. + ICU implements most of the exceptions above when determining which available named time zone identifiers are primary or non-primary. + Although use of ICU is recommended for consistency between implementations, it is not required. + Non-ICU-based implementations can still use ICU's identifier data, as found in *timezone.xml* in the Unicode Common Locale Data Repository (CLDR) https://cldr.unicode.org/. + Implementations may also build the IANA Time Zone Database directly, for example by using build options such as PACKRATDATA=backzone PACKRATLIST=zone.tab and performing any post-processing needed to ensure compliance with the requirements above.

+

+ The IANA Time Zone Database is typically updated between five and ten times per year. + 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. + ECMAScript implementations are recommended to include updates to the IANA Time Zone Database as soon as possible. + 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. +

+

+ Although the IANA Time Zone Database maintainers strive for stability, in rare cases (averaging less than once per year) a Zone may be replaced by a new Zone. + For example, in 2022 "*Europe/Kiev*" was deprecated to a Link resolving to a new "*Europe/Kyiv*" Zone. + The deprecated Link is called a renamed time zone identifier and the newly-added Zone is called a replacement time zone identifier. +

+

+ To reduce disruption from these infrequent changes, ECMAScript implementations must initially add each replacement time zone identifiers as a non-primary time zone identifier that resolves to the existing renamed time zone identifier. + This allows ECMAScript programs to recognize both identifiers, but also reduces the chance that an ECMAScript program will send the replacement time zone identifier to another system that does not yet recognize it. + After a waiting period, implementations must promote the new Zone to a primary time zone identifier while simultaneously demoting the renamed time zone identifier to non-primary. + This waiting period is two years after the IANA Time Zone Database release containing the changes, to provide ample time for other systems to be updated. + After two years, implementations should update their time zone data to make the replacement time zone identifier primary and the renamed time zone identifier non-primary. + This two-year period does not need to be exact. + For example, it's acceptable to wait until the next ICU release after two years has expired. +

+

+ A waiting period should only apply when a new Zone is added to replace an existing Zone. + If an existing Zone and Link are swapped, then no renaming has happened and no waiting period is necessary. +

+

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. 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. @@ -212,14 +303,38 @@

Use of the IANA Time Zone Database

This section complements but does not supersede .

- -

- The IANA Time Zone Database offers build options that affect which time zone identifiers are primary. - The default build options merge different countries' time zones, for example *"Atlantic/Reykjavik"* being a Link to the Zone *"Africa/Abidjan"*. - Geographically and politically distinct locations are likely to introduce divergent time zone rules in a future version of the IANA Time Zone Database. - Therefore, it is recommended that ECMAScript implementations instead use build options such as PACKRATDATA=backzone PACKRATLIST=zone.tab or a similar alternative that ensures at least one primary identifier for each ISO 3166-1 Alpha-2 country code. -

-
+ +

Unknown Time Zone

+ +

+ ECMAScript implementations must make a best effort in SystemTimeZoneIdentifier to return the primary time zone identifier that is most closely associated with the host environment's time zone. + However, in some cases the host environment's time zone cannot be determined or is not recognized, for example if the host environment uses a later version of the IANA Time Zone Database that contains newly-added identifiers that the ECMAScript implementation does not yet recognize. + In those cases, the Unknown Time Zone is used. + This time zone must behave identically to the UTC time zone, except: +

+ +

+ These differences help programmers and end users recognize that a problem exists which may require action to fix, without causing ECMAScript programs to fail whenever SystemTimeZoneIdentifier is called. +

+

+ All implementations of this specification, including implementations that will never return *"Etc/Unknown*" from SystemTimeZoneIdentifier because they share the host environment's list of available named time zone identifiers, must still treat *"Etc/Unknown"* as a primary time zone identifier, for example in the *timeZone* option of the %Intl.DateTimeFormat% constructor. +

+ +

+ In addition to helping programmers and end users identify problems, another reason this specification requires the Unknown Time Zone is to ensure compatibility with ICU https://icu.unicode.org/, the time zone library that has long been used by many ECMAScript implementations to implement SystemTimeZoneIdentifier. +

+
+
+

AvailableNamedTimeZoneIdentifiers ( ): a List of Time Zone Identifier Records

@@ -237,14 +352,37 @@

AvailableNamedTimeZoneIdentifiers ( ): a List of Time Zone Identifier Record 1. Let _identifiers_ be a List containing the String value of each Zone or Link name in the IANA Time Zone Database. 1. Assert: No element of _identifiers_ is an ASCII-case-insensitive match for any other element. 1. Assert: Every element of _identifiers_ identifies a Zone or Link name in the IANA Time Zone Database. + 1. Append *"Etc/Unknown"* to _identifiers_. 1. Sort _identifiers_ into the same order as if an Array of the same values had been sorted using %Array.prototype.sort% with *undefined* as the argument. 1. Let _result_ be a new empty List. 1. For each element _identifier_ of _identifiers_, do 1. Let _primary_ be _identifier_. - 1. If _identifier_ is a non-primary time zone identifier and _identifier_ is not *"UTC"*, then - 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. - 1. NOTE: An implementation may need to resolve _identifier_ iteratively to obtain the primary time zone identifier. - 1. If _primary_ is one of *"Etc/UTC"*, *"Etc/GMT"*, or *"GMT"*, set _primary_ to *"UTC"*. + 1. If _identifier_ is listed in the first column of Legacy POSIX Time Zone Identifier Mapping , then + 1. Set _primary_ to the value in the second column of the row where the first column is _identifier_. + 1. Else if _primary_ is *"Etc/Unknown"* or *"Factory"*, then + 1. Set _primary_ to *"Etc/Unknown"*. + 1. Else, + 1. NOTE: The algorithm steps below are intended to mimic the behaviour of the *icu::TimeZone::getIanaID()* API of the International Components for Unicode (ICU) https://icu.unicode.org/. + The steps in this section are provided for testing conformance of ICU-based ECMAScript implementations, and to ensure compatibility between ICU-based and non-ICU-based implementations. + 1. If _identifier_ is present in the *TZ* column of *zone.tab* of the IANA Time Zone Database, then + 1. Set _primary_ to _identifier_. + 1. Else if _identifier_ is a Link in the IANA Time Zone Database, then + 1. Let _zone_ be the Zone name that _identifier_ resolves to, according to the rules for resolving Link names in the IANA Time Zone Database. + 1. If _zone_ starts with *"Etc/"*, then + 1. Set _primary_ to _zone_. + 1. Else, + 1. Let _identifierCountyCode_ be the ISO 3166-2 country code https://www.iso.org/iso-3166-country-codes.html whose territory contains the geographical area corresponding to _identifier_. + 1. Let _zoneCountyCode_ be the ISO 3166-2 country code whose territory contains the geographical area corresponding to _zone_. + 1. If _identifierCountyCode_ is _zoneCountyCode_, then + 1. Set _primary_ to _zone_. + 1. Else, + 1. Let _countryCodeLine_ be the line in *zone.tab* of the IANA Time Zone Database where the *country-code* column is _identifierCountyCode_. + 1. Set _primary_ to the contents of the *TZ* column of _countryCodeLine_. + 1. If _primary_ is one of *"Etc/UTC"*, *"Etc/GMT"*, or *"GMT"*, set _primary_ to *"UTC"*. + 1. If _primary_ is a replacement time zone identifier, and it has been less than two years since the release of the IANA Time Zone Database that added the new Zone, then + 1. Set _primary_ to the renamed time zone identifier that the replacement time zone identifier is replacing. + 1. NOTE: This two year waiting period does not need to be exact, and is not required to be applied dynamically, especially in implementations that do not update time zone data between releases. + Instead, implementations may make the replacement time zone identifier primary as part of their normal release process for updating time zone data, and to release the change as close as practical to the end of the two year waiting period. 1. Let _record_ be the Time Zone Identifier Record { [[Identifier]]: _identifier_, [[PrimaryIdentifier]]: _primary_ }. 1. Append _record_ to _result_. 1. Assert: _result_ contains a Time Zone Identifier Record _r_ such that _r_.[[Identifier]] is *"UTC"* and _r_.[[PrimaryIdentifier]] is *"UTC"*.