Source code

Revision control

Copy as Markdown

Other Tools

// |reftest| shell-option(--enable-temporal) skip-if(!this.hasOwnProperty("Temporal")||!this.hasOwnProperty("Intl"))
// Ensure Intl.DateTimeFormat and Temporal return consistent year-month-day values
// for reasonable dates.
const weekdays = [
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
"Sunday",
];
// Map Hebrew months to their corresponding month code.
const hebrewMonths = {
"Tishri": "M01",
"Heshvan": "M02",
"Kislev": "M03",
"Tevet": "M04",
"Shevat": "M05",
"Adar I": "M05L",
"Adar II": "M06",
"Adar": "M06",
"Nisan": "M07",
"Iyar": "M08",
"Sivan": "M09",
"Tamuz": "M10",
"Av": "M11",
"Elul": "M12",
};
// Extract date information from a to parts formatted date.
function dateFromParts(parts) {
let relatedYear = undefined;
let year = undefined;
let monthCode = "";
let day = 0;
let dayOfWeek = -1;
for (let {type, value} of parts) {
switch (type) {
case "weekday":
dayOfWeek = weekdays.indexOf(value);
break;
case "year":
year = Number(value);
break;
case "relatedYear":
relatedYear = Number(value);
break;
case "month": {
if (value in hebrewMonths) {
monthCode = hebrewMonths[value];
} else {
// Chinese/Dangi leap months end with "bis", from Latin "bis" = "twice".
let leapMonth = value.endsWith("bis");
if (leapMonth) {
value = value.slice(0, -"bis".length);
}
monthCode = "M" + value.padStart(2, "0") + (leapMonth ? "L" : "");
}
break;
}
case "day":
day = Number(value);
break;
case "era":
case "literal":
continue;
default: throw new Error("bad part: " + type);
}
}
assertEq(dayOfWeek >= 0, true);
assertEq(monthCode.length > 0, true, JSON.stringify(parts));
assertEq(day > 0, true);
dayOfWeek += 1;
return {
relatedYear,
year,
monthCode,
day,
dayOfWeek,
};
}
const tests = {
buddhist: [
// Date ranges in 1500..2500 where ICU4C and ICU4X compute different results.
//
// NOTE: These are dates before the Gregorian change date October 15, 1582.
{
start: {iso: "1500-01-01", year: 2043, monthCode: "M01", day: 1},
end: {iso: "1582-10-14", year: 2125, monthCode: "M10", day: 14},
},
],
chinese: [
// Date ranges in 1900..2100 where ICU4C and ICU4X compute different results.
{
start: {iso: "1906-04-23", relatedYear: 1906, monthCode: "M04", day: 1},
end: {iso: "1906-05-22", relatedYear: 1906, monthCode: "M04", day: 30},
},
{
start: {iso: "1917-03-23", relatedYear: 1917, monthCode: "M02L", day: 1},
end: {iso: "1917-05-20", relatedYear: 1917, monthCode: "M03", day: 30},
},
{
start: {iso: "1922-06-25", relatedYear: 1922, monthCode: "M05L", day: 1},
end: {iso: "1922-08-22", relatedYear: 1922, monthCode: "M06", day: 30},
},
{
start: {iso: "1954-02-03", relatedYear: 1954, monthCode: "M01", day: 1},
end: {iso: "1954-03-04", relatedYear: 1954, monthCode: "M01", day: 30},
},
{
start: {iso: "1955-02-22", relatedYear: 1955, monthCode: "M02", day: 1},
end: {iso: "1955-03-23", relatedYear: 1955, monthCode: "M02", day: 30},
},
{
start: {iso: "1987-07-26", relatedYear: 1987, monthCode: "M06L", day: 1},
end: {iso: "1987-09-22", relatedYear: 1987, monthCode: "M07", day: 30},
},
{
start: {iso: "1999-01-17", relatedYear: 1998, monthCode: "M12", day: 1},
end: {iso: "1999-02-15", relatedYear: 1998, monthCode: "M12", day: 30},
},
{
start: {iso: "2012-08-17", relatedYear: 2012, monthCode: "M07", day: 1},
end: {iso: "2012-09-15", relatedYear: 2012, monthCode: "M07", day: 30},
},
{
start: {iso: "2018-11-07", relatedYear: 2018, monthCode: "M09", day: 30},
end: {iso: "2018-12-06", relatedYear: 2018, monthCode: "M10", day: 29},
},
{
start: {iso: "2027-02-06", relatedYear: 2027, monthCode: "M01", day: 1},
end: {iso: "2027-03-07", relatedYear: 2027, monthCode: "M01", day: 30},
},
{
start: {iso: "2030-02-02", relatedYear: 2029, monthCode: "M12", day: 30},
end: {iso: "2030-03-03", relatedYear: 2030, monthCode: "M01", day: 29},
},
{
start: {iso: "2057-09-28", relatedYear: 2057, monthCode: "M09", day: 1},
end: {iso: "2057-10-27", relatedYear: 2057, monthCode: "M09", day: 30},
},
{
start: {iso: "2070-03-12", relatedYear: 2070, monthCode: "M02", day: 1},
end: {iso: "2070-04-10", relatedYear: 2070, monthCode: "M02", day: 30},
},
],
dangi: [
// Date ranges in 1900..2100 where ICU4C and ICU4X compute different results.
{
start: {iso: "1904-01-17", relatedYear: 1903, monthCode: "M11", day: 30},
end: {iso: "1904-02-15", relatedYear: 1903, monthCode: "M12", day: 29},
},
{
start: {iso: "1904-11-07", relatedYear: 1904, monthCode: "M09", day: 30},
end: {iso: "1904-12-06", relatedYear: 1904, monthCode: "M10", day: 29},
},
{
start: {iso: "1905-05-04", relatedYear: 1905, monthCode: "M03", day: 30},
end: {iso: "1905-06-02", relatedYear: 1905, monthCode: "M04", day: 29},
},
{
start: {iso: "1908-04-30", relatedYear: 1908, monthCode: "M03", day: 30},
end: {iso: "1908-05-29", relatedYear: 1908, monthCode: "M04", day: 29},
},
{
start: {iso: "1911-12-20", relatedYear: 1911, monthCode: "M10", day: 30},
end: {iso: "1912-01-18", relatedYear: 1911, monthCode: "M11", day: 29},
},
{
start: {iso: "2017-02-26", relatedYear: 2017, monthCode: "M02", day: 1},
end: {iso: "2017-03-27", relatedYear: 2017, monthCode: "M02", day: 30},
},
{
start: {iso: "2051-08-06", relatedYear: 2051, monthCode: "M06", day: 30},
end: {iso: "2051-09-04", relatedYear: 2051, monthCode: "M07", day: 29},
},
{
start: {iso: "2051-11-03", relatedYear: 2051, monthCode: "M10", day: 1},
end: {iso: "2051-12-02", relatedYear: 2051, monthCode: "M10", day: 30},
},
{
start: {iso: "2097-01-13", relatedYear: 2096, monthCode: "M12", day: 1},
end: {iso: "2097-02-11", relatedYear: 2096, monthCode: "M12", day: 30},
},
],
hebrew: [
// Date ranges in 1500..2500 where ICU4C and ICU4X compute different results.
{
start: {iso: "1700-11-12", year: 5461, monthCode: "M03", day: 1},
end: {iso: "1701-12-01", year: 5462, monthCode: "M02", day: 30},
},
{
start: {iso: "1798-11-09", year: 5559, monthCode: "M03", day: 1},
end: {iso: "1799-11-28", year: 5560, monthCode: "M02", day: 30},
},
{
start: {iso: "2045-11-10", year: 5806, monthCode: "M03", day: 1},
end: {iso: "2046-11-29", year: 5807, monthCode: "M02", day: 30},
},
{
start: {iso: "2292-11-11", year: 6053, monthCode: "M03", day: 1},
end: {iso: "2293-11-30", year: 6054, monthCode: "M02", day: 30},
},
],
"islamic": [
// TODO: Not yet supported.
// Date ranges in 2000..2030 where ICU4C and ICU4X compute different results.
// {
// start: {iso: "2000-01-01", year: 1420, monthCode: "M09", day: 23},
// end: {iso: "2029-12-31", year: 1451, monthCode: "M08", day: 25},
// },
],
"islamic-umalqura": [
// TODO: Not yet supported.
// Date ranges in 2000..2030 where ICU4C and ICU4X compute different results.
// {
// start: {iso: "2000-02-06", year: 1420, monthCode: "M11", day: 1},
// end: {iso: "2000-03-06", year: 1420, monthCode: "M11", day: 30},
// },
// {
// start: {iso: "2000-09-28", year: 1421, monthCode: "M06", day: 30},
// end: {iso: "2000-10-27", year: 1421, monthCode: "M07", day: 29},
// },
// {
// start: {iso: "2001-10-17", year: 1422, monthCode: "M07", day: 30},
// end: {iso: "2001-11-15", year: 1422, monthCode: "M08", day: 29},
// },
// {
// start: {iso: "2006-06-26", year: 1427, monthCode: "M06", day: 1},
// end: {iso: "2006-07-25", year: 1427, monthCode: "M06", day: 30},
// },
// {
// start: {iso: "2024-12-02", year: 1446, monthCode: "M05", day: 30},
// end: {iso: "2024-12-31", year: 1446, monthCode: "M06", day: 29},
// },
// {
// start: {iso: "2025-01-30", year: 1446, monthCode: "M08", day: 1},
// end: {iso: "2025-02-28", year: 1446, monthCode: "M08", day: 30},
// },
// {
// start: {iso: "2029-08-11", year: 1451, monthCode: "M04", day: 1},
// end: {iso: "2029-09-09", year: 1451, monthCode: "M04", day: 30},
// },
// {
// start: {iso: "2029-11-07", year: 1451, monthCode: "M07", day: 1},
// end: {iso: "2029-12-06", year: 1451, monthCode: "M07", day: 30},
// },
],
japanese: [
// Date ranges in 1500..2500 where ICU4C and ICU4X compute different results.
//
// NOTE: These are dates before the Gregorian change date October 15, 1582.
{
start: {iso: "1500-01-01", monthCode: "M01", day: 1},
end: {iso: "1582-10-14", monthCode: "M10", day: 14},
},
],
persian: [
// Date ranges in 1500..2500 where ICU4C and ICU4X compute different results.
{
start: {iso: "2124-03-20", year: 1503, monthCode: "M01", day: 1},
end: {iso: "2125-03-20", year: 1503, monthCode: "M12", day: 30},
},
{
start: {iso: "2223-03-21", year: 1602, monthCode: "M01", day: 1},
end: {iso: "2224-03-20", year: 1602, monthCode: "M12", day: 30},
},
{
start: {iso: "2256-03-20", year: 1635, monthCode: "M01", day: 1},
end: {iso: "2257-03-20", year: 1635, monthCode: "M12", day: 30},
},
{
start: {iso: "2289-03-20", year: 1668, monthCode: "M01", day: 1},
end: {iso: "2290-03-20", year: 1668, monthCode: "M12", day: 30},
},
{
start: {iso: "2322-03-21", year: 1701, monthCode: "M01", day: 1},
end: {iso: "2323-03-21", year: 1701, monthCode: "M12", day: 30},
},
{
start: {iso: "2355-03-21", year: 1734, monthCode: "M01", day: 1},
end: {iso: "2356-03-20", year: 1734, monthCode: "M12", day: 30},
},
{
start: {iso: "2388-03-20", year: 1767, monthCode: "M01", day: 1},
end: {iso: "2389-03-20", year: 1767, monthCode: "M12", day: 30},
},
{
start: {iso: "2421-03-20", year: 1800, monthCode: "M01", day: 1},
end: {iso: "2422-03-20", year: 1800, monthCode: "M12", day: 30},
},
{
start: {iso: "2454-03-20", year: 1833, monthCode: "M01", day: 1},
end: {iso: "2455-03-20", year: 1833, monthCode: "M12", day: 30},
},
{
start: {iso: "2487-03-20", year: 1866, monthCode: "M01", day: 1},
end: {iso: "2488-03-19", year: 1866, monthCode: "M12", day: 30},
},
],
roc: [
// Date ranges in 1500..2500 where ICU4C and ICU4X compute different results.
//
// NOTE: These are dates before the Gregorian change date October 15, 1582.
{
start: {iso: "1500-01-01", eraYear: 412, monthCode: "M01", day: 1},
end: {iso: "1582-10-14", eraYear: 330, monthCode: "M10", day: 14},
},
],
};
for (let [calendar, dates] of Object.entries(tests)) {
let dtf = new Intl.DateTimeFormat("en", {
timeZone: "UTC",
calendar,
year: "numeric",
month: "numeric",
day: "numeric",
weekday: "long",
});
for (let {start, end} of dates) {
// Compute from start date.
let isoStartDate = Temporal.PlainDate.from(start.iso);
let startDate = isoStartDate.withCalendar(calendar);
let startDateParts = dtf.formatToParts(startDate);
// Compute from end date.
let isoEndDate = Temporal.PlainDate.from(end.iso);
let endDate = isoEndDate.withCalendar(calendar);
let endDateParts = dtf.formatToParts(endDate);
// Compute from ranges.
let rangeParts = dtf.formatRangeToParts(startDate, endDate);
let startRangeDateParts = rangeParts.filter(({source}) => source !== "endRange");
let endRangeDateParts = rangeParts.filter(({source}) => source !== "startRange");
// Entries to check.
let entries = [
{
date: startDate,
parts: startDateParts,
expected: start,
},
{
date: endDate,
parts: endDateParts,
expected: end,
},
{
date: startDate,
parts: startRangeDateParts,
expected: start,
},
{
date: endDate,
parts: endRangeDateParts,
expected: end,
},
];
for (let {date, parts, expected} of entries) {
// Ensure Temporal matches |expected|.
if (expected.year !== undefined) {
assertEq(date.year, expected.year);
}
if (expected.eraYear !== undefined) {
assertEq(date.eraYear, expected.eraYear);
}
if (expected.relatedYear !== undefined) {
assertEq(date.with({month: 1}).withCalendar("iso8601").year, expected.relatedYear);
}
assertEq(date.monthCode, expected.monthCode);
assertEq(date.day, expected.day);
// Ensure Intl.DateTimeFormat matches |expected|.
let partsDate = dateFromParts(parts);
if (expected.year !== undefined) {
assertEq(partsDate.year, expected.year);
}
if (expected.eraYear !== undefined) {
assertEq(partsDate.year, expected.eraYear);
}
if (partsDate.relatedYear !== undefined) {
// NB: relatedYear isn't used for range formats with chinese/dangi calendars.
assertEq(partsDate.relatedYear, expected.relatedYear);
}
assertEq(partsDate.monthCode, expected.monthCode);
assertEq(partsDate.day, expected.day);
}
}
}
if (typeof reportCompare === "function")
reportCompare(true, true);