Source code

Revision control

Copy as Markdown

Other Tools

// |reftest| skip-if(!this.hasOwnProperty("Intl")) -- Requires ICU time zone support
// The legacy POSIX-style time zones are aliases for the corresponding city time
// zones. They aren't exposed as canonical time zone identifiers, and use the
// time zone rules and localized names of the city time zones.
//
const legacyZones = {
"CST6CDT": "America/Chicago",
"EST5EDT": "America/New_York",
"MST7MDT": "America/Denver",
"PST8PDT": "America/Los_Angeles",
};
const supported = Intl.supportedValuesOf("timeZone");
// Dates before and after the transition to the modern US time zone rules.
const dates = [new Date(Date.UTC(1850, 0, 1))];
for (let year = 1900; year <= 2040; year += 4) {
for (let month = 0; month < 12; month++) {
dates.push(new Date(Date.UTC(year, month, 15, 12)));
}
}
for (let [legacy, city] of Object.entries(legacyZones)) {
// Canonicalization of the time zone identifier.
for (let id of [legacy, legacy.toLowerCase()]) {
let options = new Intl.DateTimeFormat("en-US", {timeZone: id}).resolvedOptions();
assertEq(options.timeZone, city);
}
// Not exposed as supported time zone identifiers.
assertEq(supported.includes(legacy), false);
assertEq(supported.includes(city), true);
// Localized time zone names and time zone offsets match the city.
for (let timeZoneName of ["long", "short", "longGeneric", "longOffset"]) {
let legacyDTF = new Intl.DateTimeFormat("en-US", {timeZone: legacy, timeZoneName});
let cityDTF = new Intl.DateTimeFormat("en-US", {timeZone: city, timeZoneName});
for (let date of dates) {
assertEq(legacyDTF.format(date), cityDTF.format(date));
}
}
// Date and time styles.
for (let style of ["full", "long", "medium", "short"]) {
let options = {dateStyle: style, timeStyle: style};
let legacyDTF = new Intl.DateTimeFormat("en-US", {...options, timeZone: legacy});
let cityDTF = new Intl.DateTimeFormat("en-US", {...options, timeZone: city});
for (let date of dates) {
assertEq(legacyDTF.format(date), cityDTF.format(date));
}
}
// formatToParts, formatRange, and formatRangeToParts.
{
let options = {dateStyle: "full", timeStyle: "full"};
let legacyDTF = new Intl.DateTimeFormat("en-US", {...options, timeZone: legacy});
let cityDTF = new Intl.DateTimeFormat("en-US", {...options, timeZone: city});
for (let i = 0; i < dates.length; i++) {
let start = dates[i];
let end = dates[Math.min(i + 1, dates.length - 1)];
assertDeepEq(legacyDTF.formatToParts(start), cityDTF.formatToParts(start));
assertEq(legacyDTF.formatRange(start, end), cityDTF.formatRange(start, end));
assertDeepEq(legacyDTF.formatRangeToParts(start, end),
cityDTF.formatRangeToParts(start, end));
}
}
// Date.prototype.toLocale{,Date,Time}String.
for (let date of dates) {
for (let method of ["toLocaleString", "toLocaleDateString", "toLocaleTimeString"]) {
assertEq(date[method]("en-US", {timeZone: legacy, timeZoneName: "long"}),
date[method]("en-US", {timeZone: city, timeZoneName: "long"}));
}
}
// Mozilla-only pattern option.
if (typeof addIntlExtras === "function") {
let mozIntl = {};
addIntlExtras(mozIntl);
let pattern = "yyyy-MM-dd HH:mm:ss zzzz";
let legacyDTF = new mozIntl.DateTimeFormat("en-US", {pattern, timeZone: legacy});
let cityDTF = new mozIntl.DateTimeFormat("en-US", {pattern, timeZone: city});
for (let date of dates) {
assertEq(legacyDTF.format(date), cityDTF.format(date));
}
}
if (typeof Temporal !== "undefined") {
for (let date of dates) {
let iso = date.toISOString().slice(0, 19);
let legacyZDT = Temporal.ZonedDateTime.from(`${iso}[${legacy}]`);
let cityZDT = Temporal.ZonedDateTime.from(`${iso}[${city}]`);
assertEq(legacyZDT.offset, cityZDT.offset);
assertEq(legacyZDT.epochNanoseconds, cityZDT.epochNanoseconds);
assertEq(legacyZDT.equals(cityZDT), true);
for (let timeZoneName of ["long", "short", "longGeneric"]) {
assertEq(legacyZDT.toLocaleString("en-US", {timeZoneName}),
cityZDT.toLocaleString("en-US", {timeZoneName}));
}
for (let style of ["full", "long", "medium", "short"]) {
let options = {dateStyle: style, timeStyle: style};
assertEq(legacyZDT.toLocaleString("en-US", options),
cityZDT.toLocaleString("en-US", options));
}
// Operations which depend on the time zone rules.
assertEq(legacyZDT.hoursInDay, cityZDT.hoursInDay);
assertEq(legacyZDT.startOfDay().epochNanoseconds,
cityZDT.startOfDay().epochNanoseconds);
for (let direction of ["next", "previous"]) {
let legacyTransition = legacyZDT.getTimeZoneTransition(direction);
let cityTransition = cityZDT.getTimeZoneTransition(direction);
assertEq(legacyTransition?.epochNanoseconds,
cityTransition?.epochNanoseconds);
}
let plain = cityZDT.toPlainDateTime();
assertEq(plain.toZonedDateTime(legacy).epochNanoseconds,
plain.toZonedDateTime(city).epochNanoseconds);
assertEq(cityZDT.withTimeZone(legacy).toPlainDateTime().toString(),
cityZDT.toPlainDateTime().toString());
// The identifier itself is preserved.
assertEq(legacyZDT.timeZoneId, legacy);
}
}
}
if (typeof reportCompare === "function")
reportCompare(0, 0, "ok");