Skip to content

Commit ac9ff9b

Browse files
ptomatoMs2ger
authored andcommitted
Add coverage for remapping of eras in Temporal dates
See note 2 on eras in CalendarResolveFields: https://tc39.es/proposal-temporal/#sec-temporal-calendarresolvefields This behaviour was not yet covered by any test262 tests. Based on Anba's tests from #4080 but with different behaviour.
1 parent cba890e commit ac9ff9b

File tree

2 files changed

+241
-0
lines changed

2 files changed

+241
-0
lines changed
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
// Copyright (C) 2025 Igalia, S.L. All rights reserved.
2+
// This code is governed by the BSD license found in the LICENSE file.
3+
4+
/*---
5+
esid: sec-temporal.plaindate.from
6+
description: Test remapping behaviour of regnal eras
7+
info: |
8+
CalendarDateFromFields:
9+
1. Perform ? CalendarResolveFields(_calendar_, _fields_, _date_).
10+
2. Let result be ? CalendarDateToISO(_calendar_, _fields_, _overflow_).
11+
12+
CalendarResolveFields:
13+
When the fields of _fields_ are inconsistent with respect to a non-unset
14+
_fields_.[[Era]], it is recommended that _fields_.[[Era]] and
15+
_fields_.[[EraYear]] be updated to resolve the inconsistency by lenient
16+
interpretation of out-of-bounds values (rather than throwing a *RangeError*),
17+
which is particularly useful for consistent interpretation of dates in
18+
calendars with regnal eras.
19+
20+
includes: [temporalHelpers.js]
21+
features: [Temporal]
22+
---*/
23+
24+
// Based on a test originally by André Bargull <[email protected]>
25+
26+
// Notes:
27+
// - "heisei" era started January 8, 1989.
28+
// - "reiwa" era started May 1, 2019.
29+
30+
for (const overflow of ["constrain", "reject"]) {
31+
function test(fields) {
32+
return Temporal.PlainDate.from({ ...fields, calendar: "japanese" }, { overflow });
33+
}
34+
35+
// Reiwa era started in month 5 of the year, so the era of month 1 is remapped
36+
// to be the correct one for the month.
37+
TemporalHelpers.assertPlainDate(
38+
test({ era: "reiwa", eraYear: 1, monthCode: "M01", day: 24 }),
39+
2019, 1, "M01", 24,
40+
"Reiwa 1 before May is mapped to Heisei 31",
41+
"heisei", 31
42+
);
43+
44+
// Reiwa era started on the first day of the month, so day 1 does not need
45+
// remapping.
46+
TemporalHelpers.assertPlainDate(
47+
test({ era: "reiwa", eraYear: 1, monthCode: "M05", day: 1 }),
48+
2019, 5, "M05", 1,
49+
"05-01 Reiwa 1 is not remapped",
50+
"reiwa", 1
51+
);
52+
53+
// Heisei era started on the eighth day of the month. So on previous days the
54+
// era is remapped to be the correct one for the day.
55+
TemporalHelpers.assertPlainDate(
56+
test({ era: "heisei", eraYear: 1, monthCode: "M01", day: 4 }),
57+
1989, 1, "M01", 4,
58+
"01-04 Heisei 1 is remapped to 01-04 Showa 64",
59+
"showa", 64
60+
);
61+
62+
// Era year past the end of the Heisei era is remapped to Reiwa era
63+
TemporalHelpers.assertPlainDate(
64+
test({ era: "heisei", eraYear: 37, monthCode: "M04", day: 25 }),
65+
2025, 4, "M04", 25,
66+
"Heisei 37 is remapped to Reiwa 7",
67+
"reiwa", 7
68+
);
69+
70+
// Zero year in a 1-based era is remapped to the previous era
71+
TemporalHelpers.assertPlainDate(
72+
test({ era: "reiwa", eraYear: 0, monthCode: "M04", day: 25 }),
73+
2018, 4, "M04", 25,
74+
"Reiwa 0 is remapped to Heisei 30",
75+
"heisei", 30
76+
);
77+
78+
// Negative year in a forward-counting era is remapped to the previous era
79+
TemporalHelpers.assertPlainDate(
80+
test({ era: "reiwa", eraYear: -20, monthCode: "M04", day: 25 }),
81+
1998, 4, "M04", 25,
82+
"Reiwa -20 is remapped to Heisei 10",
83+
"heisei", 10
84+
);
85+
86+
// Test the last two things for Gregorian eras as well
87+
function testGregorian(fields) {
88+
return Temporal.PlainDate.from({ ...fields, calendar: "gregory" }, { overflow });
89+
}
90+
TemporalHelpers.assertPlainDate(
91+
testGregorian({ era: "ce", eraYear: 0, monthCode: "M04", day: 25 }),
92+
0, 4, "M04", 25,
93+
"0 CE is remapped to 1 BCE",
94+
"bce", 1
95+
);
96+
TemporalHelpers.assertPlainDate(
97+
testGregorian({ era: "ce", eraYear: -20, monthCode: "M04", day: 25 }),
98+
-20, 4, "M04", 25,
99+
"-20 CE is remapped to 21 BCE",
100+
"bce", 21
101+
);
102+
103+
// Zero year in a backwards-counting era is remapped to the next era
104+
TemporalHelpers.assertPlainDate(
105+
testGregorian({ era: "bce", eraYear: 0, monthCode: "M04", day: 25 }),
106+
1, 4, "M04", 25,
107+
"0 BCE is remapped to 1 CE",
108+
"ce", 1
109+
);
110+
111+
// Negative year in a backwards-counting era is remapped to the next era
112+
TemporalHelpers.assertPlainDate(
113+
testGregorian({ era: "bce", eraYear: -20, monthCode: "M04", day: 25 }),
114+
21, 4, "M04", 25,
115+
"-20 BCE is remapped to 21 CE",
116+
"ce", 21
117+
);
118+
}
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
// Copyright (C) 2025 Igalia, S.L. All rights reserved.
2+
// This code is governed by the BSD license found in the LICENSE file.
3+
4+
/*---
5+
esid: sec-temporal.plainyearmonth.from
6+
description: Test remapping behaviour of regnal eras
7+
info: |
8+
CalendarYearMonthFromFields:
9+
1. Perform ? CalendarResolveFields(_calendar_, _fields_, ~year-month~).
10+
2. Let _firstDayIndex_ be the 1-based index of the first day of the month
11+
described by _fields_ (i.e., 1 unless the month's first day is skipped by
12+
this calendar.)
13+
3. Set _fields_.[[Day]] to _firstDayIndex_.
14+
4. Let result be ? CalendarDateToISO(_calendar_, _fields_, _overflow_).
15+
16+
CalendarResolveFields:
17+
When the fields of _fields_ are inconsistent with respect to a non-unset
18+
_fields_.[[Era]], it is recommended that _fields_.[[Era]] and
19+
_fields_.[[EraYear]] be updated to resolve the inconsistency by lenient
20+
interpretation of out-of-bounds values (rather than throwing a *RangeError*),
21+
which is particularly useful for consistent interpretation of dates in
22+
calendars with regnal eras.
23+
24+
includes: [temporalHelpers.js]
25+
features: [Temporal]
26+
---*/
27+
28+
// Based on a test originally by André Bargull <[email protected]>
29+
30+
// Notes:
31+
// - "heisei" era started January 8, 1989.
32+
// - "reiwa" era started May 1, 2019.
33+
34+
for (const overflow of ["constrain", "reject"]) {
35+
function test(fields) {
36+
return Temporal.PlainYearMonth.from({ ...fields, calendar: "japanese" }, { overflow });
37+
}
38+
39+
// Reiwa era started in month 5 of the year, so the era of month 1 is remapped
40+
// to be the correct one for the month.
41+
TemporalHelpers.assertPlainYearMonth(
42+
test({ era: "reiwa", eraYear: 1, monthCode: "M01" }),
43+
2019, 1, "M01",
44+
"Reiwa 1 before May is mapped to Heisei 31",
45+
"heisei", 31, /* reference day = */ 1
46+
);
47+
48+
// Reiwa era started on the first day of the month, so the reference day 1
49+
// does not need remapping.
50+
TemporalHelpers.assertPlainYearMonth(
51+
test({ era: "reiwa", eraYear: 1, monthCode: "M05" }),
52+
2019, 5, "M05",
53+
"reference day is 1",
54+
"reiwa", 1, /* reference day = */ 1
55+
);
56+
57+
// Heisei era started on the eighth day of the month, but PlainYearMonth
58+
// references the first day of the month. So the era is remapped to be the
59+
// correct one for the reference day.
60+
TemporalHelpers.assertPlainYearMonth(
61+
test({ era: "heisei", eraYear: 1, monthCode: "M01" }),
62+
1989, 1, "M01",
63+
"01-01 Heisei 1 is remapped to 01-01 Showa 64",
64+
"showa", 64, /* reference day = */ 1
65+
);
66+
67+
// Era year past the end of the Heisei era is remapped to Reiwa era
68+
TemporalHelpers.assertPlainYearMonth(
69+
test({ era: "heisei", eraYear: 37, monthCode: "M04" }),
70+
2025, 4, "M04",
71+
"Heisei 37 is remapped to Reiwa 7",
72+
"reiwa", 7, /* reference day = */ 1
73+
);
74+
75+
// Zero year in a 1-based era is remapped to the previous era
76+
TemporalHelpers.assertPlainYearMonth(
77+
test({ era: "reiwa", eraYear: 0, monthCode: "M04" }),
78+
2018, 4, "M04",
79+
"Reiwa 0 is remapped to Heisei 30",
80+
"heisei", 30, /* reference day = */ 1
81+
);
82+
83+
// Negative year in a forwards-counting era is remapped to the previous era
84+
TemporalHelpers.assertPlainYearMonth(
85+
test({ era: "reiwa", eraYear: -20, monthCode: "M04" }),
86+
1998, 4, "M04",
87+
"Reiwa -20 is remapped to Heisei 10",
88+
"heisei", 10, /* reference day = */ 1
89+
);
90+
91+
// Test the last two things for Gregorian eras as well
92+
function testGregorian(fields) {
93+
return Temporal.PlainYearMonth.from({ ...fields, calendar: "gregory" }, { overflow });
94+
}
95+
TemporalHelpers.assertPlainYearMonth(
96+
testGregorian({ era: "ce", eraYear: 0, monthCode: "M04" }),
97+
0, 4, "M04",
98+
"0 CE is remapped to 1 BCE",
99+
"bce", 1, /* reference day = */ 1
100+
);
101+
TemporalHelpers.assertPlainYearMonth(
102+
testGregorian({ era: "ce", eraYear: -20, monthCode: "M04" }),
103+
-20, 4, "M04",
104+
"-20 CE is remapped to 21 BCE",
105+
"bce", 21, /* reference day = */ 1
106+
);
107+
108+
// Zero year in a backwards-counting era is remapped to the next era
109+
TemporalHelpers.assertPlainYearMonth(
110+
testGregorian({ era: "bce", eraYear: 0, monthCode: "M04" }),
111+
1, 4, "M04",
112+
"0 BCE is remapped to 1 CE",
113+
"ce", 1, /* reference day = */ 1
114+
);
115+
116+
// Negative year in a backwards-counting era is remapped to the next era
117+
TemporalHelpers.assertPlainYearMonth(
118+
testGregorian({ era: "bce", eraYear: -20, monthCode: "M04" }),
119+
21, 4, "M04",
120+
"-20 BCE is remapped to 21 CE",
121+
"ce", 21, /* reference day = */ 1
122+
);
123+
}

0 commit comments

Comments
 (0)