Bug 1930466 - Part 1: Use zone.tab to guide time zone canonicalisation. r=dminor

Implement the changes from <https://github.com/tc39/ecma402/pull/877> to reduce
differences in time zone canonicalisation when compared to V8 and JSC (which
both use CLDR time zone data instead of IANA time zone data).

Implementing the `AvailableNamedTimeZoneIdentifiers` spec operation requires to
link time zone identifiers to region codes. When the time zone is listed in the
"zone.tab" file, we can get the region code from "zone.tab". In all other cases
we need to manually map the time zone to a matching region, because CLDR doesn't
have "public" data for this [1]. This is implemented using the new file
"intl/TimeZoneMapping.yaml".

ICU 74 added `ucal_getIanaTimeZoneID` to get the canonical IANA time zone id.
Internally `ucal_getIanaTimeZoneID` first calls `ucal_getCanonicalTimeZoneID`
and then loads a resource bundle to check if there are any time zone ids which
need to be replaced with other ids for compatibility with IANA data. Unfortunately
the resource bundle is not cached, so calling `ucal_getIanaTimeZoneID` instead
of `ucal_getIanaTimeZoneID` adds a considerable performance overhead. To avoid
any performance regressions, we keep our own time zone rewriting code for the
time being.

Using our own code also means we don't have to add a workaround for this CLDR
bug: <https://unicode-org.atlassian.net/browse/CLDR-16439>.

Also remove "Factory" from the list of supported time zone identifiers, because
supporting it was always a bit questionable and latest V8 also doesn't support
it anymore, so we shouldn't run into web-compat issues.

Remove the old generated tests and add "timeZone_links.js" to ensure time zone
links are correctly resolved.

[1] Neither of these two files look like "public" data to me:
- https://github.com/unicode-org/cldr/blob/main/tools/cldr-code/src/main/resources/org/unicode/cldr/util/data/TZID.txt
- https://github.com/unicode-org/cldr/blob/main/tools/cldr-code/src/main/resources/org/unicode/cldr/icu/idList.txt

Differential Revision: https://phabricator.services.mozilla.com/D228584
This commit is contained in:
André Bargull
2024-11-27 07:08:16 +00:00
parent b394406ee9
commit 11d9f06f26
11 changed files with 446 additions and 605 deletions

View File

@@ -7,10 +7,10 @@
async function verifySpoofed() {
ok(true, "Running on " + content.location.origin);
SpecialPowers.Cu.getJSTestingFunctions().setTimeZone("PST8PDT");
SpecialPowers.Cu.getJSTestingFunctions().setTimeZone("America/Los_Angeles");
is(
Intl.DateTimeFormat("en-US").resolvedOptions().timeZone,
"PST8PDT",
"America/Los_Angeles",
"Default time zone should have changed"
);
@@ -113,10 +113,10 @@ add_task(async function test_timezone_exempt() {
});
await SpecialPowers.spawn(tab.linkedBrowser, [], async function () {
SpecialPowers.Cu.getJSTestingFunctions().setTimeZone("PST8PDT");
SpecialPowers.Cu.getJSTestingFunctions().setTimeZone("America/Los_Angeles");
is(
Intl.DateTimeFormat("en-US").resolvedOptions().timeZone,
"PST8PDT",
"America/Los_Angeles",
"Default time zone should have changed"
);
@@ -129,7 +129,7 @@ add_task(async function test_timezone_exempt() {
is(
Intl.DateTimeFormat("en-US").resolvedOptions().timeZone,
"PST8PDT",
"America/Los_Angeles",
"Content should use default time zone"
);
}
@@ -169,10 +169,10 @@ add_task(async function test_timezone_exempt_wrong_domain() {
});
add_task(async function test_timezone_exmpt_browser() {
SpecialPowers.Cu.getJSTestingFunctions().setTimeZone("PST8PDT");
SpecialPowers.Cu.getJSTestingFunctions().setTimeZone("America/Los_Angeles");
is(
Intl.DateTimeFormat("en-US").resolvedOptions().timeZone,
"PST8PDT",
"America/Los_Angeles",
"Default time zone should have changed"
);
@@ -182,7 +182,7 @@ add_task(async function test_timezone_exmpt_browser() {
is(
Intl.DateTimeFormat("en-US").resolvedOptions().timeZone,
"PST8PDT",
"America/Los_Angeles",
"Timezone in chrome should be unaffected by resistFingerprinting"
);
@@ -196,7 +196,7 @@ add_task(async function test_timezone_exmpt_browser() {
is(
newWindow.Intl.DateTimeFormat("en-US").resolvedOptions().timeZone,
"PST8PDT",
"America/Los_Angeles",
"Timezone in new chrome window should be unaffected by resistFingerprinting"
);

View File

@@ -10,58 +10,26 @@ namespace timezone {
// Format:
// "ZoneName" // ICU-Name [time zone file]
const char* const ianaZonesTreatedAsLinksByICU[] = {
"Africa/Asmara", // Africa/Asmera [backzone]
"Africa/Timbuktu", // Africa/Bamako [backzone]
"Africa/Asmara", // Africa/Asmera [backward]
"America/Argentina/Buenos_Aires", // America/Buenos_Aires [southamerica]
"America/Argentina/Catamarca", // America/Catamarca [southamerica]
"America/Argentina/ComodRivadavia", // America/Catamarca [backzone]
"America/Argentina/Cordoba", // America/Cordoba [southamerica]
"America/Argentina/Jujuy", // America/Jujuy [southamerica]
"America/Argentina/Mendoza", // America/Mendoza [southamerica]
"America/Atikokan", // America/Coral_Harbour [backzone]
"America/Ensenada", // America/Tijuana [backzone]
"America/Atikokan", // America/Coral_Harbour [backward]
"America/Indiana/Indianapolis", // America/Indianapolis [northamerica]
"America/Kentucky/Louisville", // America/Louisville [northamerica]
"America/Montreal", // America/Toronto [backzone]
"America/Nipigon", // America/Toronto [backzone]
"America/Nuuk", // America/Godthab [europe]
"America/Pangnirtung", // America/Iqaluit [backzone]
"America/Rainy_River", // America/Winnipeg [backzone]
"America/Rosario", // America/Cordoba [backzone]
"America/Thunder_Bay", // America/Toronto [backzone]
"America/Yellowknife", // America/Edmonton [backzone]
"Asia/Chongqing", // Asia/Shanghai [backzone]
"Asia/Harbin", // Asia/Shanghai [backzone]
"Asia/Ho_Chi_Minh", // Asia/Saigon [asia]
"Asia/Kashgar", // Asia/Urumqi [backzone]
"Asia/Kathmandu", // Asia/Katmandu [asia]
"Asia/Kolkata", // Asia/Calcutta [asia]
"Asia/Tel_Aviv", // Asia/Jerusalem [backzone]
"Asia/Yangon", // Asia/Rangoon [asia]
"Atlantic/Faroe", // Atlantic/Faeroe [europe]
"Atlantic/Jan_Mayen", // Arctic/Longyearbyen [backzone]
"Australia/Currie", // Australia/Hobart [backzone]
"CET", // Europe/Brussels [backzone]
"CST6CDT", // America/Chicago [backzone]
"EET", // Europe/Athens [backzone]
"EST", // America/Panama [backzone]
"EST5EDT", // America/New_York [backzone]
"Europe/Belfast", // Europe/London [backzone]
"Europe/Kyiv", // Europe/Kiev [europe]
"Europe/Tiraspol", // Europe/Chisinau [backzone]
"Europe/Uzhgorod", // Europe/Kiev [backzone]
"Europe/Zaporozhye", // Europe/Kiev [backzone]
"Factory", // Etc/Unknown [factory]
"HST", // Pacific/Honolulu [backzone]
"MET", // Europe/Brussels [backzone]
"MST", // America/Phoenix [backzone]
"MST7MDT", // America/Denver [backzone]
"PST8PDT", // America/Los_Angeles [backzone]
"Pacific/Chuuk", // Pacific/Truk [backzone]
"Pacific/Johnston", // Pacific/Honolulu [backzone]
"Pacific/Chuuk", // Pacific/Truk [backward]
"Pacific/Kanton", // Pacific/Enderbury [australasia]
"Pacific/Pohnpei", // Pacific/Ponape [backzone]
"WET", // Europe/Lisbon [backzone]
"Pacific/Pohnpei", // Pacific/Ponape [backward]
"UTC", // Etc/UTC [backward]
};
// Format:
@@ -74,38 +42,49 @@ struct LinkAndTarget
const LinkAndTarget ianaLinksCanonicalizedDifferentlyByICU[] = {
{ "Africa/Asmera", "Africa/Asmara" }, // Africa/Asmera [backward]
{ "America/Argentina/ComodRivadavia", "America/Argentina/Catamarca" }, // America/Catamarca [backward]
{ "America/Buenos_Aires", "America/Argentina/Buenos_Aires" }, // America/Buenos_Aires [backward]
{ "America/Catamarca", "America/Argentina/Catamarca" }, // America/Catamarca [backward]
{ "America/Coral_Harbour", "America/Atikokan" }, // America/Coral_Harbour [backward]
{ "America/Cordoba", "America/Argentina/Cordoba" }, // America/Cordoba [backward]
{ "America/Fort_Wayne", "America/Indiana/Indianapolis" }, // America/Indianapolis [backward]
{ "America/Godthab", "America/Nuuk" }, // America/Godthab [backward]
{ "America/Indianapolis", "America/Indiana/Indianapolis" }, // America/Indianapolis [backward]
{ "America/Jujuy", "America/Argentina/Jujuy" }, // America/Jujuy [backward]
{ "America/Kralendijk", "America/Curacao" }, // America/Kralendijk [backward]
{ "America/Louisville", "America/Kentucky/Louisville" }, // America/Louisville [backward]
{ "America/Lower_Princes", "America/Curacao" }, // America/Lower_Princes [backward]
{ "America/Marigot", "America/Port_of_Spain" }, // America/Marigot [backward]
{ "America/Mendoza", "America/Argentina/Mendoza" }, // America/Mendoza [backward]
{ "America/St_Barthelemy", "America/Port_of_Spain" }, // America/St_Barthelemy [backward]
{ "America/Rosario", "America/Argentina/Cordoba" }, // America/Cordoba [backward]
{ "Antarctica/South_Pole", "Antarctica/McMurdo" }, // Pacific/Auckland [backward]
{ "Arctic/Longyearbyen", "Europe/Oslo" }, // Arctic/Longyearbyen [backward]
{ "Asia/Calcutta", "Asia/Kolkata" }, // Asia/Calcutta [backward]
{ "Asia/Chungking", "Asia/Chongqing" }, // Asia/Shanghai [backward]
{ "Asia/Katmandu", "Asia/Kathmandu" }, // Asia/Katmandu [backward]
{ "Asia/Rangoon", "Asia/Yangon" }, // Asia/Rangoon [backward]
{ "Asia/Saigon", "Asia/Ho_Chi_Minh" }, // Asia/Saigon [backward]
{ "Atlantic/Faeroe", "Atlantic/Faroe" }, // Atlantic/Faeroe [backward]
{ "Europe/Bratislava", "Europe/Prague" }, // Europe/Bratislava [backward]
{ "Europe/Busingen", "Europe/Zurich" }, // Europe/Busingen [backward]
{ "Etc/GMT", "UTC" }, // Etc/GMT [etcetera]
{ "Etc/GMT+0", "UTC" }, // Etc/GMT [backward]
{ "Etc/GMT-0", "UTC" }, // Etc/GMT [backward]
{ "Etc/GMT0", "UTC" }, // Etc/GMT [backward]
{ "Etc/Greenwich", "UTC" }, // Etc/GMT [backward]
{ "Etc/UCT", "UTC" }, // Etc/UTC [backward]
{ "Etc/UTC", "UTC" }, // Etc/UTC [etcetera]
{ "Etc/Universal", "UTC" }, // Etc/UTC [backward]
{ "Etc/Zulu", "UTC" }, // Etc/UTC [backward]
{ "Europe/Kiev", "Europe/Kyiv" }, // Europe/Kiev [backward]
{ "Europe/Mariehamn", "Europe/Helsinki" }, // Europe/Mariehamn [backward]
{ "Europe/Podgorica", "Europe/Belgrade" }, // Europe/Podgorica [backward]
{ "Europe/San_Marino", "Europe/Rome" }, // Europe/San_Marino [backward]
{ "Europe/Vatican", "Europe/Rome" }, // Europe/Vatican [backward]
{ "Europe/Uzhgorod", "Europe/Kyiv" }, // Europe/Kiev [backward]
{ "Europe/Zaporozhye", "Europe/Kyiv" }, // Europe/Kiev [backward]
{ "GMT", "UTC" }, // Etc/GMT [etcetera]
{ "GMT+0", "UTC" }, // Etc/GMT [backward]
{ "GMT-0", "UTC" }, // Etc/GMT [backward]
{ "GMT0", "UTC" }, // Etc/GMT [backward]
{ "Greenwich", "UTC" }, // Etc/GMT [backward]
{ "Pacific/Enderbury", "Pacific/Kanton" }, // Pacific/Enderbury [backward]
{ "Pacific/Ponape", "Pacific/Pohnpei" }, // Pacific/Ponape [backward]
{ "Pacific/Truk", "Pacific/Chuuk" }, // Pacific/Truk [backward]
{ "Pacific/Yap", "Pacific/Chuuk" }, // Pacific/Truk [backward]
{ "UCT", "UTC" }, // Etc/UTC [backward]
{ "US/East-Indiana", "America/Indiana/Indianapolis" }, // America/Indianapolis [backward]
{ "Universal", "UTC" }, // Etc/UTC [backward]
{ "Zulu", "UTC" }, // Etc/UTC [backward]
};
// Legacy ICU time zones, these are not valid IANA time zone names. We also
@@ -139,6 +118,7 @@ const char* const legacyICUTimeZones[] = {
"SST",
"US/Pacific-New",
"VST",
"Factory",
"SystemV/AST4",
"SystemV/AST4ADT",
"SystemV/CST6",

View File

@@ -0,0 +1,157 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
# Provide mapping from time zone identifiers to region codes for time zones
# which aren't listed in tzdata's zone.tab file.
Africa/Timbuktu: ML
Africa/Asmera: ER
America/Argentina/ComodRivadavia: AR
America/Atka: US
America/Buenos_Aires: AR
America/Catamarca: AR
America/Coral_Harbour: CA
America/Cordoba: AR
America/Ensenada: MX
America/Fort_Wayne: US
America/Godthab: GL
America/Indianapolis: US
America/Jujuy: AR
America/Knox_IN: US
America/Louisville: US
America/Mendoza: AR
America/Montreal: CA
America/Nipigon: CA
America/Pangnirtung: CA
America/Porto_Acre: BR
America/Rainy_River: CA
America/Rosario: AR
America/Santa_Isabel: MX
America/Shiprock: US
America/Thunder_Bay: CA
America/Virgin: VI
America/Yellowknife: CA
Antarctica/South_Pole: AQ
Asia/Choibalsan: MN
Asia/Chongqing: CN
Asia/Harbin: CN
Asia/Kashgar: CN
Asia/Tel_Aviv: IL
Asia/Ashkhabad: TM
Asia/Calcutta: IN
Asia/Chungking: CN
Asia/Dacca: BD
Asia/Istanbul: TR
Asia/Katmandu: NP
Asia/Macao: MO
Asia/Rangoon: MM
Asia/Saigon: VN
Asia/Thimbu: BT
Asia/Ujung_Pandang: ID
Asia/Ulan_Bator: MN
Atlantic/Jan_Mayen: SJ
Atlantic/Faeroe: FO
Australia/ACT: AU
Australia/LHI: AU
Australia/NSW: AU
Australia/Canberra: AU
Australia/Currie: AU
Australia/North: AU
Australia/Queensland: AU
Australia/South: AU
Australia/Tasmania: AU
Australia/Victoria: AU
Australia/West: AU
Australia/Yancowinna: AU
Europe/Belfast: GB
Europe/Tiraspol: MD
Europe/Uzhgorod: UA
Europe/Zaporozhye: UA
Europe/Kiev: UA
Europe/Nicosia: CY
Pacific/Samoa: AS
Pacific/Enderbury: KI
Pacific/Johnston: US
Pacific/Yap: FM
Pacific/Ponape: FM
Pacific/Truk: FM
Brazil/Acre: BR
Brazil/DeNoronha: BR
Brazil/East: BR
Brazil/West: BR
Canada/Atlantic: CA
Canada/Central: CA
Canada/Eastern: CA
Canada/Mountain: CA
Canada/Newfoundland: CA
Canada/Pacific: CA
Canada/Saskatchewan: CA
Canada/Yukon: CA
Chile/Continental: CL
Chile/EasterIsland: CL
Mexico/BajaNorte: MX
Mexico/BajaSur: MX
Mexico/General: MX
US/Alaska: US
US/Aleutian: US
US/Arizona: US
US/Central: US
US/East-Indiana: US
US/Eastern: US
US/Hawaii: US
US/Indiana-Starke: US
US/Michigan: US
US/Mountain: US
US/Pacific: US
US/Samoa: AS
CET: BE
EET: GR
MET: BE
WET: PT
CST6CDT: US
EST5EDT: US
EST: PA
HST: US
MST7MDT: US
MST: US
PST8PDT: US
Cuba: CU
Egypt: EG
Eire: IE
GB: GB
GB-Eire: GB
Hongkong: HK
Iceland: IS
Iran: IR
Israel: IL
Jamaica: JM
Japan: JP
Kwajalein: MH
Libya: LY
NZ: NZ
NZ-CHAT: NZ
Navajo: US
PRC: CN
Poland: PL
Portugal: PT
ROC: TW
ROK: KR
Singapore: SG
Turkey: TR
W-SU: RU

View File

@@ -45,32 +45,19 @@ import io
import json
import os
import re
import sys
import tarfile
import tempfile
from contextlib import closing
from functools import partial, total_ordering
from itertools import chain, groupby, tee
from itertools import chain, filterfalse, groupby, tee, zip_longest
from operator import attrgetter, itemgetter
from urllib.parse import urlsplit
from urllib.request import Request as UrlRequest
from urllib.request import urlopen
from zipfile import ZipFile
import yaml
if sys.version_info.major == 2:
from itertools import ifilter as filter
from itertools import ifilterfalse as filterfalse
from itertools import imap as map
from itertools import izip_longest as zip_longest
from urllib2 import Request as UrlRequest
from urllib2 import urlopen
from urlparse import urlsplit
else:
from itertools import filterfalse, zip_longest
from urllib.parse import urlsplit
from urllib.request import Request as UrlRequest
from urllib.request import urlopen
# From https://docs.python.org/3/library/itertools.html
def grouper(iterable, n, fillvalue=None):
@@ -2215,7 +2202,8 @@ def readIANAFiles(tzdataDir, files):
nameSyntax = r"[\w/+\-]+"
pZone = re.compile(r"Zone\s+(?P<name>%s)\s+.*" % nameSyntax)
pLink = re.compile(
r"Link\s+(?P<target>%s)\s+(?P<name>%s)(?:\s+#.*)?" % (nameSyntax, nameSyntax)
r"(#PACKRATLIST\s+zone.tab\s+)?Link\s+(?P<target>%s)\s+(?P<name>%s)(?:\s+#.*)?"
% (nameSyntax, nameSyntax)
)
def createZone(line, fname):
@@ -2230,6 +2218,7 @@ def readIANAFiles(tzdataDir, files):
zones = set()
links = dict()
packrat_links = dict()
for filename in files:
filepath = tzdataDir.resolve(filename)
for line in tzdataDir.readlines(filepath):
@@ -2238,31 +2227,26 @@ def readIANAFiles(tzdataDir, files):
if line.startswith("Link"):
(link, target) = createLink(line, filename)
links[link] = target
if line.startswith("#PACKRATLIST zone.tab Link"):
(link, target) = createLink(line, filename)
packrat_links[link] = target
return (zones, links)
return (zones, links, packrat_links)
def readIANATimeZones(tzdataDir, ignoreBackzone, ignoreFactory):
def readIANATimeZones(tzdataDir, ignoreFactory):
"""Read the IANA time zone information from `tzdataDir`."""
backzoneFiles = {"backzone"}
(bkfiles, tzfiles) = partition(listIANAFiles(tzdataDir), backzoneFiles.__contains__)
files_to_ignore = ["backzone"]
# Ignore the placeholder time zone "Factory".
if ignoreFactory:
files_to_ignore.append("factory")
tzfiles = (file for file in listIANAFiles(tzdataDir) if file not in files_to_ignore)
# Read zone and link infos.
(zones, links) = readIANAFiles(tzdataDir, tzfiles)
(backzones, backlinks) = readIANAFiles(tzdataDir, bkfiles)
# Remove the placeholder time zone "Factory".
if ignoreFactory:
zones.remove(Zone("Factory"))
# Merge with backzone data.
if not ignoreBackzone:
zones |= backzones
links = {
name: target for name, target in links.items() if name not in backzones
}
links.update(backlinks)
(zones, links, _) = readIANAFiles(tzdataDir, tzfiles)
validateTimeZones(zones, links)
@@ -2431,7 +2415,13 @@ def readICUTimeZones(icuDir, icuTzDir, ignoreFactory):
# Remove the placeholder time zone "Factory".
# See also <https://github.com/eggert/tz/blob/master/factory>.
if ignoreFactory:
assert Zone("Factory") in zoneinfoZones
assert Zone("Factory") not in zoneinfoLinks
assert Zone("Factory") not in typesZones
assert Zone("Factory") in typesLinks
zoneinfoZones.remove(Zone("Factory"))
del typesLinks[Zone("Factory")]
# Remove the ICU placeholder time zone "Etc/Unknown".
# See also <https://unicode.org/reports/tr35/#Time_Zone_Identifiers>.
@@ -2497,7 +2487,7 @@ def readICULegacyZones(icuDir):
# non-IANA time zones and links.
# Most legacy, non-IANA time zones and links are in the icuzones file.
(zones, links) = readIANAFiles(tzdir, ["icuzones"])
(zones, links, _) = readIANAFiles(tzdir, ["icuzones"])
# Remove the ICU placeholder time zone "Etc/Unknown".
# See also <https://unicode.org/reports/tr35/#Time_Zone_Identifiers>.
@@ -2561,7 +2551,7 @@ def icuTzDataVersion(icuTzDir):
return version
def findIncorrectICUZones(ianaZones, ianaLinks, icuZones, icuLinks, ignoreBackzone):
def findIncorrectICUZones(ianaZones, ianaLinks, icuZones, icuLinks):
"""Find incorrect ICU zone entries."""
def isIANATimeZone(zone):
@@ -2575,11 +2565,7 @@ def findIncorrectICUZones(ianaZones, ianaLinks, icuZones, icuLinks, ignoreBackzo
# All IANA zones should be present in ICU.
missingTimeZones = [zone for zone in ianaZones if not isICUTimeZone(zone)]
# Normally zones in backzone are also present as links in one of the other
# time zone files. The only exception to this rule is the Asia/Hanoi time
# zone, this zone is only present in the backzone file.
expectedMissing = [] if ignoreBackzone else [Zone("Asia/Hanoi")]
if missingTimeZones != expectedMissing:
if missingTimeZones:
raise RuntimeError(
"Not all zones are present in ICU, did you forget "
"to run intl/update-tzdata.sh? %s" % missingTimeZones
@@ -2660,28 +2646,157 @@ def findIncorrectICULinks(ianaZones, ianaLinks, icuZones, icuLinks):
return sorted(result, key=itemgetter(0))
def readZoneTab(tzdataDir):
zone_country = dict()
zonetab_path = tzdataDir.resolve("zone.tab")
for line in tzdataDir.readlines(zonetab_path):
if line.startswith("#"):
continue
(country, coords, zone, *comments) = line.strip().split("\t")
assert zone not in zone_country
zone_country[zone] = country
return zone_country
# 6.5.1 AvailableNamedTimeZoneIdentifiers ( )
#
# https://tc39.es/ecma402/#sup-availablenamedtimezoneidentifiers
def availableNamedTimeZoneIdentifiers(tzdataDir, ignoreFactory):
js_src_builtin_intl_dir = os.path.dirname(os.path.abspath(__file__))
with io.open(
os.path.join(js_src_builtin_intl_dir, "TimeZoneMapping.yaml"),
mode="r",
encoding="utf-8",
) as f:
time_zone_mapping = yaml.safe_load(f)
zone_country = readZoneTab(tzdataDir)
def country_code_for(name):
if name in zone_country:
return zone_country[name]
return time_zone_mapping[name]
(ianaZones, ianaLinks) = readIANATimeZones(tzdataDir, ignoreFactory)
(backzones, backlinks, packratlinks) = readIANAFiles(tzdataDir, ["backzone"])
all_backzone_links = {**backlinks, **packratlinks}
# Steps 1-3. (Not applicable)
# Step 4.
zones = set()
links = dict()
# Step 5. (Partial, only zones)
for zone in ianaZones:
# Step 5.a.
primary = zone
# Step 5.b. (Not applicable for zones)
# Step 5.c.
if primary.name in ["Etc/UTC", "Etc/GMT", "GMT"]:
primary = Zone("UTC", primary.filename)
# Step 5.d. (Not applicable)
# Steps 5.e-f.
if primary == zone:
assert zone not in zones
zones.add(primary)
else:
assert zone not in links
links[zone] = primary.name
# Step 5. (Partial, only links)
for zone, target in ianaLinks.items():
identifier = zone.name
# Step 5.a.
primary = identifier
# Step 5.b.
if identifier not in zone_country:
# Step 5.b.i. (Not applicable)
# Steps 5.b.ii-iii.
if target.startswith("Etc/"):
primary = target
else:
# Step 5.b.iii.1.
identifier_code_code = country_code_for(identifier)
# Step 5.b.iii.2.
target_code_code = country_code_for(target)
# Steps 5.b.iii.3-4
if identifier_code_code == target_code_code:
primary = target
else:
# Step 5.b.iii.4.a.
country_code_line_count = [
zone
for (zone, code) in zone_country.items()
if code == identifier_code_code
]
# Steps 5.b.iii.4.b-c.
if len(country_code_line_count) == 1:
primary = country_code_line_count[0]
else:
assert Zone(identifier) in all_backzone_links
primary = all_backzone_links[Zone(identifier)]
assert identifier_code_code == country_code_for(primary)
# Step 5.c.
if primary in ["Etc/UTC", "Etc/GMT", "GMT"]:
primary = "UTC"
# Step 5.d. (Not applicable)
# Steps 5.e-f.
if primary == identifier:
assert zone not in zones
zones.add(zone)
else:
assert zone not in links
links[zone] = primary
# Ensure all zones and links are valid.
validateTimeZones(zones, links)
# Step 6.
assert Zone("UTC") in zones
# Step 7.
return (zones, links)
generatedFileWarning = "// Generated by make_intl_data.py. DO NOT EDIT."
tzdataVersionComment = "// tzdata version = {0}"
def processTimeZones(
tzdataDir, icuDir, icuTzDir, version, ignoreBackzone, ignoreFactory, out
):
def processTimeZones(tzdataDir, icuDir, icuTzDir, version, ignoreFactory, out):
"""Read the time zone info and create a new time zone cpp file."""
print("Processing tzdata mapping...")
(ianaZones, ianaLinks) = readIANATimeZones(tzdataDir, ignoreBackzone, ignoreFactory)
(ianaZones, ianaLinks) = availableNamedTimeZoneIdentifiers(tzdataDir, ignoreFactory)
(icuZones, icuLinks) = readICUTimeZones(icuDir, icuTzDir, ignoreFactory)
(legacyZones, legacyLinks) = readICULegacyZones(icuDir)
if ignoreFactory:
legacyZones.add(Zone("Factory"))
# Remove all legacy ICU time zones.
icuZones = {zone for zone in icuZones if zone not in legacyZones}
icuLinks = {
zone: target for (zone, target) in icuLinks.items() if zone not in legacyLinks
}
incorrectZones = findIncorrectICUZones(
ianaZones, ianaLinks, icuZones, icuLinks, ignoreBackzone
)
incorrectZones = findIncorrectICUZones(ianaZones, ianaLinks, icuZones, icuLinks)
if not incorrectZones:
print("<<< No incorrect ICU time zones found, please update Intl.js! >>>")
print("<<< Maybe https://ssl.icu-project.org/trac/ticket/12044 was fixed? >>>")
@@ -2751,28 +2866,12 @@ def processTimeZones(
println("#endif /* builtin_intl_TimeZoneDataGenerated_h */")
def updateBackzoneLinks(tzdataDir, links):
def withZone(fn):
return lambda zone_target: fn(zone_target[0])
def generateTzDataTestLinks(tzdataDir, version, ignoreFactory, testDir):
fileName = "timeZone_links.js"
(backzoneZones, backzoneLinks) = readIANAFiles(tzdataDir, ["backzone"])
(stableZones, updatedLinks, updatedZones) = partition(
links.items(),
# Link not changed in backzone.
withZone(lambda zone: zone not in backzoneLinks and zone not in backzoneZones),
# Link has a new target.
withZone(lambda zone: zone in backzoneLinks),
)
# Keep stable zones and links with updated target.
return dict(
chain(
stableZones,
map(withZone(lambda zone: (zone, backzoneLinks[zone])), updatedLinks),
)
)
# Read zone and link infos.
(_, links) = availableNamedTimeZoneIdentifiers(tzdataDir, ignoreFactory)
def generateTzDataLinkTestContent(testDir, version, fileName, description, links):
with io.open(
os.path.join(testDir, fileName), mode="w", encoding="utf-8", newline=""
) as f:
@@ -2792,9 +2891,9 @@ const tzMapper = [
"""
)
println(description)
println("// Link names derived from IANA Time Zone Database.")
println("const links = {")
for zone, target in sorted(links, key=itemgetter(0)):
for zone, target in sorted(links.items(), key=itemgetter(0)):
println(' "%s": "%s",' % (zone, target))
println("};")
@@ -2820,112 +2919,6 @@ if (typeof reportCompare === "function")
)
def generateTzDataTestBackwardLinks(tzdataDir, version, ignoreBackzone, testDir):
(zones, links) = readIANAFiles(tzdataDir, ["backward"])
assert len(zones) == 0
if not ignoreBackzone:
links = updateBackzoneLinks(tzdataDir, links)
generateTzDataLinkTestContent(
testDir,
version,
"timeZone_backward_links.js",
"// Link names derived from IANA Time Zone Database, backward file.",
links.items(),
)
def generateTzDataTestNotBackwardLinks(tzdataDir, version, ignoreBackzone, testDir):
tzfiles = filterfalse(
{"backward", "backzone"}.__contains__, listIANAFiles(tzdataDir)
)
(zones, links) = readIANAFiles(tzdataDir, tzfiles)
if not ignoreBackzone:
links = updateBackzoneLinks(tzdataDir, links)
generateTzDataLinkTestContent(
testDir,
version,
"timeZone_notbackward_links.js",
"// Link names derived from IANA Time Zone Database, excluding backward file.",
links.items(),
)
def generateTzDataTestBackzone(tzdataDir, version, ignoreBackzone, testDir):
backzoneFiles = {"backzone"}
(bkfiles, tzfiles) = partition(listIANAFiles(tzdataDir), backzoneFiles.__contains__)
# Read zone and link infos.
(zones, links) = readIANAFiles(tzdataDir, tzfiles)
(backzones, backlinks) = readIANAFiles(tzdataDir, bkfiles)
if not ignoreBackzone:
comment = """\
// This file was generated with historical, pre-1970 backzone information
// respected. Therefore, every zone key listed below is its own Zone, not
// a Link to a modern-day target as IANA ignoring backzones would say.
"""
else:
comment = """\
// This file was generated while ignoring historical, pre-1970 backzone
// information. Therefore, every zone key listed below is part of a Link
// whose target is the corresponding value.
"""
generateTzDataLinkTestContent(
testDir,
version,
"timeZone_backzone.js",
comment + "// Backzone zones derived from IANA Time Zone Database.",
(
(zone, zone if not ignoreBackzone else links[zone])
for zone in backzones
if zone in links
),
)
def generateTzDataTestBackzoneLinks(tzdataDir, version, ignoreBackzone, testDir):
backzoneFiles = {"backzone"}
(bkfiles, tzfiles) = partition(listIANAFiles(tzdataDir), backzoneFiles.__contains__)
# Read zone and link infos.
(zones, links) = readIANAFiles(tzdataDir, tzfiles)
(backzones, backlinks) = readIANAFiles(tzdataDir, bkfiles)
if not ignoreBackzone:
comment = """\
// This file was generated with historical, pre-1970 backzone information
// respected. Therefore, every zone key listed below points to a target
// in the backzone file and not to its modern-day target as IANA ignoring
// backzones would say.
"""
else:
comment = """\
// This file was generated while ignoring historical, pre-1970 backzone
// information. Therefore, every zone key listed below is part of a Link
// whose target is the corresponding value ignoring any backzone entries.
"""
generateTzDataLinkTestContent(
testDir,
version,
"timeZone_backzone_links.js",
comment + "// Backzone links derived from IANA Time Zone Database.",
(
(zone, target if not ignoreBackzone else links[zone])
for (zone, target) in backlinks.items()
),
)
def generateTzDataTestVersion(tzdataDir, version, testDir):
fileName = "timeZone_version.js"
@@ -2956,32 +2949,11 @@ if (typeof reportCompare === "function")
)
def generateTzDataTestCanonicalZones(
tzdataDir, version, ignoreBackzone, ignoreFactory, testDir
):
def generateTzDataTestCanonicalZones(tzdataDir, version, ignoreFactory, testDir):
fileName = "supportedValuesOf-timeZones-canonical.js"
# Read zone and link infos.
(ianaZones, _) = readIANATimeZones(tzdataDir, ignoreBackzone, ignoreFactory)
# Replace Etc/GMT and Etc/UTC with UTC.
ianaZones.remove(Zone("Etc/GMT"))
ianaZones.remove(Zone("Etc/UTC"))
ianaZones.add(Zone("UTC"))
# See findIncorrectICUZones() for why Asia/Hanoi has to be special-cased.
ianaZones.remove(Zone("Asia/Hanoi"))
if not ignoreBackzone:
comment = """\
// This file was generated with historical, pre-1970 backzone information
// respected.
"""
else:
comment = """\
// This file was generated while ignoring historical, pre-1970 backzone
// information.
"""
(zones, _) = availableNamedTimeZoneIdentifiers(tzdataDir, ignoreFactory)
with io.open(
os.path.join(testDir, fileName), mode="w", encoding="utf-8", newline=""
@@ -2992,11 +2964,9 @@ def generateTzDataTestCanonicalZones(
println("")
println(generatedFileWarning)
println(tzdataVersionComment.format(version))
println("")
println(comment)
println("const zones = [")
for zone in sorted(ianaZones):
for zone in sorted(zones):
println(f' "{zone}",')
println("];")
@@ -3012,19 +2982,14 @@ if (typeof reportCompare === "function")
)
def generateTzDataTests(tzdataDir, version, ignoreBackzone, ignoreFactory, testDir):
def generateTzDataTests(tzdataDir, version, ignoreFactory, testDir):
dtfTestDir = os.path.join(testDir, "DateTimeFormat")
if not os.path.isdir(dtfTestDir):
raise RuntimeError("not a directory: %s" % dtfTestDir)
generateTzDataTestBackwardLinks(tzdataDir, version, ignoreBackzone, dtfTestDir)
generateTzDataTestNotBackwardLinks(tzdataDir, version, ignoreBackzone, dtfTestDir)
generateTzDataTestBackzone(tzdataDir, version, ignoreBackzone, dtfTestDir)
generateTzDataTestBackzoneLinks(tzdataDir, version, ignoreBackzone, dtfTestDir)
generateTzDataTestLinks(tzdataDir, version, ignoreFactory, dtfTestDir)
generateTzDataTestVersion(tzdataDir, version, dtfTestDir)
generateTzDataTestCanonicalZones(
tzdataDir, version, ignoreBackzone, ignoreFactory, testDir
)
generateTzDataTestCanonicalZones(tzdataDir, version, ignoreFactory, testDir)
def updateTzdata(topsrcdir, args):
@@ -3045,11 +3010,11 @@ def updateTzdata(topsrcdir, args):
tzDir = args.tz
if tzDir is not None and not (os.path.isdir(tzDir) or os.path.isfile(tzDir)):
raise RuntimeError("not a directory or file: %s" % tzDir)
ignoreBackzone = args.ignore_backzone
# TODO: Accept or ignore the placeholder time zone "Factory"?
ignoreFactory = False
out = args.out
# Ignore the placeholder time zone "Factory".
ignoreFactory = True
version = icuTzDataVersion(icuTzDir)
url = (
"https://www.iana.org/time-zones/repository/releases/tzdata%s.tar.gz" % version
@@ -3061,7 +3026,6 @@ def updateTzdata(topsrcdir, args):
print("\ttzdata directory|file: %s" % tzDir)
print("\tICU directory: %s" % icuDir)
print("\tICU timezone directory: %s" % icuTzDir)
print("\tIgnore backzone file: %s" % ignoreBackzone)
print("\tOutput file: %s" % out)
print("")
@@ -3073,12 +3037,11 @@ def updateTzdata(topsrcdir, args):
icuDir,
icuTzDir,
version,
ignoreBackzone,
ignoreFactory,
out,
)
generateTzDataTests(
TzDataFile(tar), version, ignoreBackzone, ignoreFactory, intlTestDir
TzDataFile(tar), version, ignoreFactory, intlTestDir
)
elif os.path.isdir(f):
processTimeZones(
@@ -3086,13 +3049,10 @@ def updateTzdata(topsrcdir, args):
icuDir,
icuTzDir,
version,
ignoreBackzone,
ignoreFactory,
out,
)
generateTzDataTests(
TzDataDir(f), version, ignoreBackzone, ignoreFactory, intlTestDir
)
generateTzDataTests(TzDataDir(f), version, ignoreFactory, intlTestDir)
else:
raise RuntimeError("unknown format")
@@ -4084,17 +4044,6 @@ if __name__ == "__main__":
help="Local tzdata directory or file, if omitted downloads tzdata "
"distribution from https://www.iana.org/time-zones/",
)
# ICU doesn't include the backzone file by default, but we still like to
# use the backzone time zone names to avoid user confusion. This does lead
# to formatting "historic" dates (pre-1970 era) with the wrong time zone,
# but that's probably acceptable for now.
parser_tz.add_argument(
"--ignore-backzone",
action="store_true",
help="Ignore tzdata's 'backzone' file. Can be enabled to generate more "
"accurate time zone canonicalization reflecting the actual time "
"zones as used by ICU.",
)
parser_tz.add_argument(
"--out",
default=os.path.join(thisDir, "TimeZoneDataGenerated.h"),

View File

@@ -14,7 +14,7 @@ let originalDT = Intl.DateTimeFormat("en-US", {
timeStyle: "full",
});
assertEq(originalDT.format(original).endsWith("Pacific Standard Time"), true);
assertEq(originalDT.resolvedOptions().timeZone, "PST8PDT");
assertEq(originalDT.resolvedOptions().timeZone, "America/Los_Angeles");
let global = newGlobal({forceUTC: true});

View File

@@ -1,163 +0,0 @@
// |reftest| skip-if(!this.hasOwnProperty("Intl"))
// Generated by make_intl_data.py. DO NOT EDIT.
// tzdata version = 2024b
const tzMapper = [
x => x,
x => x.toUpperCase(),
x => x.toLowerCase(),
];
// This file was generated with historical, pre-1970 backzone information
// respected. Therefore, every zone key listed below is its own Zone, not
// a Link to a modern-day target as IANA ignoring backzones would say.
// Backzone zones derived from IANA Time Zone Database.
const links = {
"Africa/Accra": "Africa/Accra",
"Africa/Addis_Ababa": "Africa/Addis_Ababa",
"Africa/Asmara": "Africa/Asmara",
"Africa/Bamako": "Africa/Bamako",
"Africa/Bangui": "Africa/Bangui",
"Africa/Banjul": "Africa/Banjul",
"Africa/Blantyre": "Africa/Blantyre",
"Africa/Brazzaville": "Africa/Brazzaville",
"Africa/Bujumbura": "Africa/Bujumbura",
"Africa/Conakry": "Africa/Conakry",
"Africa/Dakar": "Africa/Dakar",
"Africa/Dar_es_Salaam": "Africa/Dar_es_Salaam",
"Africa/Djibouti": "Africa/Djibouti",
"Africa/Douala": "Africa/Douala",
"Africa/Freetown": "Africa/Freetown",
"Africa/Gaborone": "Africa/Gaborone",
"Africa/Harare": "Africa/Harare",
"Africa/Kampala": "Africa/Kampala",
"Africa/Kigali": "Africa/Kigali",
"Africa/Kinshasa": "Africa/Kinshasa",
"Africa/Libreville": "Africa/Libreville",
"Africa/Lome": "Africa/Lome",
"Africa/Luanda": "Africa/Luanda",
"Africa/Lubumbashi": "Africa/Lubumbashi",
"Africa/Lusaka": "Africa/Lusaka",
"Africa/Malabo": "Africa/Malabo",
"Africa/Maseru": "Africa/Maseru",
"Africa/Mbabane": "Africa/Mbabane",
"Africa/Mogadishu": "Africa/Mogadishu",
"Africa/Niamey": "Africa/Niamey",
"Africa/Nouakchott": "Africa/Nouakchott",
"Africa/Ouagadougou": "Africa/Ouagadougou",
"Africa/Porto-Novo": "Africa/Porto-Novo",
"Africa/Timbuktu": "Africa/Timbuktu",
"America/Anguilla": "America/Anguilla",
"America/Antigua": "America/Antigua",
"America/Argentina/ComodRivadavia": "America/Argentina/ComodRivadavia",
"America/Aruba": "America/Aruba",
"America/Atikokan": "America/Atikokan",
"America/Blanc-Sablon": "America/Blanc-Sablon",
"America/Cayman": "America/Cayman",
"America/Coral_Harbour": "America/Coral_Harbour",
"America/Creston": "America/Creston",
"America/Curacao": "America/Curacao",
"America/Dominica": "America/Dominica",
"America/Ensenada": "America/Ensenada",
"America/Grenada": "America/Grenada",
"America/Guadeloupe": "America/Guadeloupe",
"America/Montreal": "America/Montreal",
"America/Montserrat": "America/Montserrat",
"America/Nassau": "America/Nassau",
"America/Nipigon": "America/Nipigon",
"America/Pangnirtung": "America/Pangnirtung",
"America/Port_of_Spain": "America/Port_of_Spain",
"America/Rainy_River": "America/Rainy_River",
"America/Rosario": "America/Rosario",
"America/St_Kitts": "America/St_Kitts",
"America/St_Lucia": "America/St_Lucia",
"America/St_Thomas": "America/St_Thomas",
"America/St_Vincent": "America/St_Vincent",
"America/Thunder_Bay": "America/Thunder_Bay",
"America/Tortola": "America/Tortola",
"America/Yellowknife": "America/Yellowknife",
"Antarctica/DumontDUrville": "Antarctica/DumontDUrville",
"Antarctica/McMurdo": "Antarctica/McMurdo",
"Antarctica/Syowa": "Antarctica/Syowa",
"Asia/Aden": "Asia/Aden",
"Asia/Bahrain": "Asia/Bahrain",
"Asia/Brunei": "Asia/Brunei",
"Asia/Chongqing": "Asia/Chongqing",
"Asia/Harbin": "Asia/Harbin",
"Asia/Kashgar": "Asia/Kashgar",
"Asia/Kuala_Lumpur": "Asia/Kuala_Lumpur",
"Asia/Kuwait": "Asia/Kuwait",
"Asia/Muscat": "Asia/Muscat",
"Asia/Phnom_Penh": "Asia/Phnom_Penh",
"Asia/Tel_Aviv": "Asia/Tel_Aviv",
"Asia/Vientiane": "Asia/Vientiane",
"Atlantic/Jan_Mayen": "Atlantic/Jan_Mayen",
"Atlantic/Reykjavik": "Atlantic/Reykjavik",
"Atlantic/St_Helena": "Atlantic/St_Helena",
"Australia/Currie": "Australia/Currie",
"CET": "CET",
"CST6CDT": "CST6CDT",
"EET": "EET",
"EST": "EST",
"EST5EDT": "EST5EDT",
"Europe/Amsterdam": "Europe/Amsterdam",
"Europe/Belfast": "Europe/Belfast",
"Europe/Copenhagen": "Europe/Copenhagen",
"Europe/Guernsey": "Europe/Guernsey",
"Europe/Isle_of_Man": "Europe/Isle_of_Man",
"Europe/Jersey": "Europe/Jersey",
"Europe/Ljubljana": "Europe/Ljubljana",
"Europe/Luxembourg": "Europe/Luxembourg",
"Europe/Monaco": "Europe/Monaco",
"Europe/Oslo": "Europe/Oslo",
"Europe/Sarajevo": "Europe/Sarajevo",
"Europe/Skopje": "Europe/Skopje",
"Europe/Stockholm": "Europe/Stockholm",
"Europe/Tiraspol": "Europe/Tiraspol",
"Europe/Uzhgorod": "Europe/Uzhgorod",
"Europe/Vaduz": "Europe/Vaduz",
"Europe/Zagreb": "Europe/Zagreb",
"Europe/Zaporozhye": "Europe/Zaporozhye",
"HST": "HST",
"Indian/Antananarivo": "Indian/Antananarivo",
"Indian/Christmas": "Indian/Christmas",
"Indian/Cocos": "Indian/Cocos",
"Indian/Comoro": "Indian/Comoro",
"Indian/Kerguelen": "Indian/Kerguelen",
"Indian/Mahe": "Indian/Mahe",
"Indian/Mayotte": "Indian/Mayotte",
"Indian/Reunion": "Indian/Reunion",
"MET": "MET",
"MST": "MST",
"MST7MDT": "MST7MDT",
"PST8PDT": "PST8PDT",
"Pacific/Chuuk": "Pacific/Chuuk",
"Pacific/Enderbury": "Pacific/Enderbury",
"Pacific/Funafuti": "Pacific/Funafuti",
"Pacific/Johnston": "Pacific/Johnston",
"Pacific/Majuro": "Pacific/Majuro",
"Pacific/Midway": "Pacific/Midway",
"Pacific/Pohnpei": "Pacific/Pohnpei",
"Pacific/Saipan": "Pacific/Saipan",
"Pacific/Wake": "Pacific/Wake",
"Pacific/Wallis": "Pacific/Wallis",
"WET": "WET",
};
for (let [linkName, target] of Object.entries(links)) {
if (target === "Etc/UTC" || target === "Etc/GMT")
target = "UTC";
for (let map of tzMapper) {
let dtf = new Intl.DateTimeFormat(undefined, {timeZone: map(linkName)});
let resolvedTimeZone = dtf.resolvedOptions().timeZone;
assertEq(resolvedTimeZone, target, `${linkName} -> ${target}`);
}
}
if (typeof reportCompare === "function")
reportCompare(0, 0, "ok");

View File

@@ -1,48 +0,0 @@
// |reftest| skip-if(!this.hasOwnProperty("Intl"))
// Generated by make_intl_data.py. DO NOT EDIT.
// tzdata version = 2024b
const tzMapper = [
x => x,
x => x.toUpperCase(),
x => x.toLowerCase(),
];
// This file was generated with historical, pre-1970 backzone information
// respected. Therefore, every zone key listed below points to a target
// in the backzone file and not to its modern-day target as IANA ignoring
// backzones would say.
// Backzone links derived from IANA Time Zone Database.
const links = {
"Africa/Asmera": "Africa/Asmara",
"America/Kralendijk": "America/Curacao",
"America/Lower_Princes": "America/Curacao",
"America/Marigot": "America/Port_of_Spain",
"America/St_Barthelemy": "America/Port_of_Spain",
"America/Virgin": "America/St_Thomas",
"Antarctica/South_Pole": "Antarctica/McMurdo",
"Arctic/Longyearbyen": "Europe/Oslo",
"Asia/Chungking": "Asia/Chongqing",
"Iceland": "Atlantic/Reykjavik",
"Pacific/Ponape": "Pacific/Pohnpei",
"Pacific/Truk": "Pacific/Chuuk",
"Pacific/Yap": "Pacific/Chuuk",
};
for (let [linkName, target] of Object.entries(links)) {
if (target === "Etc/UTC" || target === "Etc/GMT")
target = "UTC";
for (let map of tzMapper) {
let dtf = new Intl.DateTimeFormat(undefined, {timeZone: map(linkName)});
let resolvedTimeZone = dtf.resolvedOptions().timeZone;
assertEq(resolvedTimeZone, target, `${linkName} -> ${target}`);
}
}
if (typeof reportCompare === "function")
reportCompare(0, 0, "ok");

View File

@@ -9,46 +9,58 @@ const tzMapper = [
x => x.toLowerCase(),
];
// Link names derived from IANA Time Zone Database, backward file.
// Link names derived from IANA Time Zone Database.
const links = {
"Africa/Asmera": "Africa/Asmara",
"Africa/Timbuktu": "Africa/Bamako",
"America/Argentina/ComodRivadavia": "America/Argentina/Catamarca",
"America/Atka": "America/Adak",
"America/Buenos_Aires": "America/Argentina/Buenos_Aires",
"America/Catamarca": "America/Argentina/Catamarca",
"America/Coral_Harbour": "America/Atikokan",
"America/Cordoba": "America/Argentina/Cordoba",
"America/Ensenada": "America/Tijuana",
"America/Fort_Wayne": "America/Indiana/Indianapolis",
"America/Godthab": "America/Nuuk",
"America/Indianapolis": "America/Indiana/Indianapolis",
"America/Jujuy": "America/Argentina/Jujuy",
"America/Knox_IN": "America/Indiana/Knox",
"America/Kralendijk": "America/Curacao",
"America/Louisville": "America/Kentucky/Louisville",
"America/Lower_Princes": "America/Curacao",
"America/Marigot": "America/Port_of_Spain",
"America/Mendoza": "America/Argentina/Mendoza",
"America/Montreal": "America/Toronto",
"America/Nipigon": "America/Toronto",
"America/Pangnirtung": "America/Iqaluit",
"America/Porto_Acre": "America/Rio_Branco",
"America/Rainy_River": "America/Winnipeg",
"America/Rosario": "America/Argentina/Cordoba",
"America/Santa_Isabel": "America/Tijuana",
"America/Shiprock": "America/Denver",
"America/St_Barthelemy": "America/Port_of_Spain",
"America/Thunder_Bay": "America/Toronto",
"America/Virgin": "America/St_Thomas",
"America/Yellowknife": "America/Edmonton",
"Antarctica/South_Pole": "Antarctica/McMurdo",
"Arctic/Longyearbyen": "Europe/Oslo",
"Asia/Ashkhabad": "Asia/Ashgabat",
"Asia/Calcutta": "Asia/Kolkata",
"Asia/Choibalsan": "Asia/Ulaanbaatar",
"Asia/Chungking": "Asia/Chongqing",
"Asia/Chongqing": "Asia/Shanghai",
"Asia/Chungking": "Asia/Shanghai",
"Asia/Dacca": "Asia/Dhaka",
"Asia/Harbin": "Asia/Shanghai",
"Asia/Istanbul": "Europe/Istanbul",
"Asia/Kashgar": "Asia/Urumqi",
"Asia/Katmandu": "Asia/Kathmandu",
"Asia/Macao": "Asia/Macau",
"Asia/Rangoon": "Asia/Yangon",
"Asia/Saigon": "Asia/Ho_Chi_Minh",
"Asia/Tel_Aviv": "Asia/Jerusalem",
"Asia/Thimbu": "Asia/Thimphu",
"Asia/Ujung_Pandang": "Asia/Makassar",
"Asia/Ulan_Bator": "Asia/Ulaanbaatar",
"Atlantic/Faeroe": "Atlantic/Faroe",
"Atlantic/Jan_Mayen": "Arctic/Longyearbyen",
"Australia/ACT": "Australia/Sydney",
"Australia/Canberra": "Australia/Sydney",
"Australia/Currie": "Australia/Hobart",
"Australia/LHI": "Australia/Lord_Howe",
"Australia/NSW": "Australia/Sydney",
"Australia/North": "Australia/Darwin",
@@ -62,6 +74,8 @@ const links = {
"Brazil/DeNoronha": "America/Noronha",
"Brazil/East": "America/Sao_Paulo",
"Brazil/West": "America/Manaus",
"CET": "Europe/Brussels",
"CST6CDT": "America/Chicago",
"Canada/Atlantic": "America/Halifax",
"Canada/Central": "America/Winnipeg",
"Canada/Eastern": "America/Toronto",
@@ -73,29 +87,34 @@ const links = {
"Chile/Continental": "America/Santiago",
"Chile/EasterIsland": "Pacific/Easter",
"Cuba": "America/Havana",
"EET": "Europe/Athens",
"EST": "America/Panama",
"EST5EDT": "America/New_York",
"Egypt": "Africa/Cairo",
"Eire": "Europe/Dublin",
"Etc/GMT+0": "Etc/GMT",
"Etc/GMT-0": "Etc/GMT",
"Etc/GMT0": "Etc/GMT",
"Etc/Greenwich": "Etc/GMT",
"Etc/UCT": "Etc/UTC",
"Etc/Universal": "Etc/UTC",
"Etc/Zulu": "Etc/UTC",
"Europe/Bratislava": "Europe/Prague",
"Europe/Busingen": "Europe/Zurich",
"Etc/GMT": "UTC",
"Etc/GMT+0": "UTC",
"Etc/GMT-0": "UTC",
"Etc/GMT0": "UTC",
"Etc/Greenwich": "UTC",
"Etc/UCT": "UTC",
"Etc/UTC": "UTC",
"Etc/Universal": "UTC",
"Etc/Zulu": "UTC",
"Europe/Belfast": "Europe/London",
"Europe/Kiev": "Europe/Kyiv",
"Europe/Mariehamn": "Europe/Helsinki",
"Europe/Nicosia": "Asia/Nicosia",
"Europe/Podgorica": "Europe/Belgrade",
"Europe/San_Marino": "Europe/Rome",
"Europe/Vatican": "Europe/Rome",
"Europe/Tiraspol": "Europe/Chisinau",
"Europe/Uzhgorod": "Europe/Kyiv",
"Europe/Zaporozhye": "Europe/Kyiv",
"GB": "Europe/London",
"GB-Eire": "Europe/London",
"GMT+0": "Etc/GMT",
"GMT-0": "Etc/GMT",
"GMT0": "Etc/GMT",
"Greenwich": "Etc/GMT",
"GMT": "UTC",
"GMT+0": "UTC",
"GMT-0": "UTC",
"GMT0": "UTC",
"Greenwich": "UTC",
"HST": "Pacific/Honolulu",
"Hongkong": "Asia/Hong_Kong",
"Iceland": "Atlantic/Reykjavik",
"Iran": "Asia/Tehran",
@@ -104,6 +123,9 @@ const links = {
"Japan": "Asia/Tokyo",
"Kwajalein": "Pacific/Kwajalein",
"Libya": "Africa/Tripoli",
"MET": "Europe/Brussels",
"MST": "America/Phoenix",
"MST7MDT": "America/Denver",
"Mexico/BajaNorte": "America/Tijuana",
"Mexico/BajaSur": "America/Mazatlan",
"Mexico/General": "America/Mexico_City",
@@ -111,6 +133,9 @@ const links = {
"NZ-CHAT": "Pacific/Chatham",
"Navajo": "America/Denver",
"PRC": "Asia/Shanghai",
"PST8PDT": "America/Los_Angeles",
"Pacific/Enderbury": "Pacific/Kanton",
"Pacific/Johnston": "Pacific/Honolulu",
"Pacific/Ponape": "Pacific/Pohnpei",
"Pacific/Samoa": "Pacific/Pago_Pago",
"Pacific/Truk": "Pacific/Chuuk",
@@ -121,7 +146,7 @@ const links = {
"ROK": "Asia/Seoul",
"Singapore": "Asia/Singapore",
"Turkey": "Europe/Istanbul",
"UCT": "Etc/UTC",
"UCT": "UTC",
"US/Alaska": "America/Anchorage",
"US/Aleutian": "America/Adak",
"US/Arizona": "America/Phoenix",
@@ -134,10 +159,10 @@ const links = {
"US/Mountain": "America/Denver",
"US/Pacific": "America/Los_Angeles",
"US/Samoa": "Pacific/Pago_Pago",
"UTC": "Etc/UTC",
"Universal": "Etc/UTC",
"Universal": "UTC",
"W-SU": "Europe/Moscow",
"Zulu": "Etc/UTC",
"WET": "Europe/Lisbon",
"Zulu": "UTC",
};
for (let [linkName, target] of Object.entries(links)) {

View File

@@ -1,31 +0,0 @@
// |reftest| skip-if(!this.hasOwnProperty("Intl"))
// Generated by make_intl_data.py. DO NOT EDIT.
// tzdata version = 2024b
const tzMapper = [
x => x,
x => x.toUpperCase(),
x => x.toLowerCase(),
];
// Link names derived from IANA Time Zone Database, excluding backward file.
const links = {
"GMT": "Etc/GMT",
};
for (let [linkName, target] of Object.entries(links)) {
if (target === "Etc/UTC" || target === "Etc/GMT")
target = "UTC";
for (let map of tzMapper) {
let dtf = new Intl.DateTimeFormat(undefined, {timeZone: map(linkName)});
let resolvedTimeZone = dtf.resolvedOptions().timeZone;
assertEq(resolvedTimeZone, target, `${linkName} -> ${target}`);
}
}
if (typeof reportCompare === "function")
reportCompare(0, 0, "ok");

View File

@@ -40,10 +40,10 @@ function inTimeZone(tzname, fn) {
}
const timeZones = [
{ id: "EST5EDT" },
{ id: "CST6CDT" },
{ id: "MST7MDT" },
{ id: "PST8PDT" },
{ id: "EST5EDT", normalized: "America/New_York" },
{ id: "CST6CDT", normalized: "America/Chicago" },
{ id: "MST7MDT", normalized: "America/Denver" },
{ id: "PST8PDT", normalized: "America/Los_Angeles" },
// ICU on non-Windows platforms doesn't accept these three time zone
// identifiers, cf. isValidOlsonID in $ICU/source/common/putil.cpp. We
// could add support for them, but it seems unlikely they're used in

View File

@@ -2,10 +2,6 @@
// Generated by make_intl_data.py. DO NOT EDIT.
// tzdata version = 2024b
// This file was generated with historical, pre-1970 backzone information
// respected.
const zones = [
"Africa/Abidjan",
"Africa/Accra",
@@ -56,7 +52,6 @@ const zones = [
"Africa/Ouagadougou",
"Africa/Porto-Novo",
"Africa/Sao_Tome",
"Africa/Timbuktu",
"Africa/Tripoli",
"Africa/Tunis",
"Africa/Windhoek",
@@ -67,7 +62,6 @@ const zones = [
"America/Araguaina",
"America/Argentina/Buenos_Aires",
"America/Argentina/Catamarca",
"America/Argentina/ComodRivadavia",
"America/Argentina/Cordoba",
"America/Argentina/Jujuy",
"America/Argentina/La_Rioja",
@@ -99,7 +93,6 @@ const zones = [
"America/Chicago",
"America/Chihuahua",
"America/Ciudad_Juarez",
"America/Coral_Harbour",
"America/Costa_Rica",
"America/Creston",
"America/Cuiaba",
@@ -113,7 +106,6 @@ const zones = [
"America/Edmonton",
"America/Eirunepe",
"America/El_Salvador",
"America/Ensenada",
"America/Fort_Nelson",
"America/Fortaleza",
"America/Glace_Bay",
@@ -141,12 +133,15 @@ const zones = [
"America/Juneau",
"America/Kentucky/Louisville",
"America/Kentucky/Monticello",
"America/Kralendijk",
"America/La_Paz",
"America/Lima",
"America/Los_Angeles",
"America/Lower_Princes",
"America/Maceio",
"America/Managua",
"America/Manaus",
"America/Marigot",
"America/Martinique",
"America/Matamoros",
"America/Mazatlan",
@@ -158,11 +153,9 @@ const zones = [
"America/Moncton",
"America/Monterrey",
"America/Montevideo",
"America/Montreal",
"America/Montserrat",
"America/Nassau",
"America/New_York",
"America/Nipigon",
"America/Nome",
"America/Noronha",
"America/North_Dakota/Beulah",
@@ -171,7 +164,6 @@ const zones = [
"America/Nuuk",
"America/Ojinaga",
"America/Panama",
"America/Pangnirtung",
"America/Paramaribo",
"America/Phoenix",
"America/Port-au-Prince",
@@ -179,19 +171,18 @@ const zones = [
"America/Porto_Velho",
"America/Puerto_Rico",
"America/Punta_Arenas",
"America/Rainy_River",
"America/Rankin_Inlet",
"America/Recife",
"America/Regina",
"America/Resolute",
"America/Rio_Branco",
"America/Rosario",
"America/Santarem",
"America/Santiago",
"America/Santo_Domingo",
"America/Sao_Paulo",
"America/Scoresbysund",
"America/Sitka",
"America/St_Barthelemy",
"America/St_Johns",
"America/St_Kitts",
"America/St_Lucia",
@@ -200,7 +191,6 @@ const zones = [
"America/Swift_Current",
"America/Tegucigalpa",
"America/Thule",
"America/Thunder_Bay",
"America/Tijuana",
"America/Toronto",
"America/Tortola",
@@ -208,7 +198,6 @@ const zones = [
"America/Whitehorse",
"America/Winnipeg",
"America/Yakutat",
"America/Yellowknife",
"Antarctica/Casey",
"Antarctica/Davis",
"Antarctica/DumontDUrville",
@@ -220,6 +209,7 @@ const zones = [
"Antarctica/Syowa",
"Antarctica/Troll",
"Antarctica/Vostok",
"Arctic/Longyearbyen",
"Asia/Aden",
"Asia/Almaty",
"Asia/Amman",
@@ -237,7 +227,6 @@ const zones = [
"Asia/Bishkek",
"Asia/Brunei",
"Asia/Chita",
"Asia/Chongqing",
"Asia/Colombo",
"Asia/Damascus",
"Asia/Dhaka",
@@ -246,7 +235,6 @@ const zones = [
"Asia/Dushanbe",
"Asia/Famagusta",
"Asia/Gaza",
"Asia/Harbin",
"Asia/Hebron",
"Asia/Ho_Chi_Minh",
"Asia/Hong_Kong",
@@ -258,7 +246,6 @@ const zones = [
"Asia/Kabul",
"Asia/Kamchatka",
"Asia/Karachi",
"Asia/Kashgar",
"Asia/Kathmandu",
"Asia/Khandyga",
"Asia/Kolkata",
@@ -293,7 +280,6 @@ const zones = [
"Asia/Tashkent",
"Asia/Tbilisi",
"Asia/Tehran",
"Asia/Tel_Aviv",
"Asia/Thimphu",
"Asia/Tokyo",
"Asia/Tomsk",
@@ -311,7 +297,6 @@ const zones = [
"Atlantic/Canary",
"Atlantic/Cape_Verde",
"Atlantic/Faroe",
"Atlantic/Jan_Mayen",
"Atlantic/Madeira",
"Atlantic/Reykjavik",
"Atlantic/South_Georgia",
@@ -320,7 +305,6 @@ const zones = [
"Australia/Adelaide",
"Australia/Brisbane",
"Australia/Broken_Hill",
"Australia/Currie",
"Australia/Darwin",
"Australia/Eucla",
"Australia/Hobart",
@@ -329,11 +313,6 @@ const zones = [
"Australia/Melbourne",
"Australia/Perth",
"Australia/Sydney",
"CET",
"CST6CDT",
"EET",
"EST",
"EST5EDT",
"Etc/GMT+1",
"Etc/GMT+10",
"Etc/GMT+11",
@@ -364,12 +343,13 @@ const zones = [
"Europe/Andorra",
"Europe/Astrakhan",
"Europe/Athens",
"Europe/Belfast",
"Europe/Belgrade",
"Europe/Berlin",
"Europe/Bratislava",
"Europe/Brussels",
"Europe/Bucharest",
"Europe/Budapest",
"Europe/Busingen",
"Europe/Chisinau",
"Europe/Copenhagen",
"Europe/Dublin",
@@ -388,15 +368,18 @@ const zones = [
"Europe/Luxembourg",
"Europe/Madrid",
"Europe/Malta",
"Europe/Mariehamn",
"Europe/Minsk",
"Europe/Monaco",
"Europe/Moscow",
"Europe/Oslo",
"Europe/Paris",
"Europe/Podgorica",
"Europe/Prague",
"Europe/Riga",
"Europe/Rome",
"Europe/Samara",
"Europe/San_Marino",
"Europe/Sarajevo",
"Europe/Saratov",
"Europe/Simferopol",
@@ -405,19 +388,15 @@ const zones = [
"Europe/Stockholm",
"Europe/Tallinn",
"Europe/Tirane",
"Europe/Tiraspol",
"Europe/Ulyanovsk",
"Europe/Uzhgorod",
"Europe/Vaduz",
"Europe/Vatican",
"Europe/Vienna",
"Europe/Vilnius",
"Europe/Volgograd",
"Europe/Warsaw",
"Europe/Zagreb",
"Europe/Zaporozhye",
"Europe/Zurich",
"Factory",
"HST",
"Indian/Antananarivo",
"Indian/Chagos",
"Indian/Christmas",
@@ -429,10 +408,6 @@ const zones = [
"Indian/Mauritius",
"Indian/Mayotte",
"Indian/Reunion",
"MET",
"MST",
"MST7MDT",
"PST8PDT",
"Pacific/Apia",
"Pacific/Auckland",
"Pacific/Bougainville",
@@ -440,7 +415,6 @@ const zones = [
"Pacific/Chuuk",
"Pacific/Easter",
"Pacific/Efate",
"Pacific/Enderbury",
"Pacific/Fakaofo",
"Pacific/Fiji",
"Pacific/Funafuti",
@@ -449,7 +423,6 @@ const zones = [
"Pacific/Guadalcanal",
"Pacific/Guam",
"Pacific/Honolulu",
"Pacific/Johnston",
"Pacific/Kanton",
"Pacific/Kiritimati",
"Pacific/Kosrae",
@@ -474,7 +447,6 @@ const zones = [
"Pacific/Wake",
"Pacific/Wallis",
"UTC",
"WET",
];
let supported = Intl.supportedValuesOf("timeZone");