diff --git a/Jint.Tests.Test262/Test262Harness.settings.json b/Jint.Tests.Test262/Test262Harness.settings.json
index 6a334e9a8f..82d81b92da 100644
--- a/Jint.Tests.Test262/Test262Harness.settings.json
+++ b/Jint.Tests.Test262/Test262Harness.settings.json
@@ -144,62 +144,8 @@
// .NET ar-EG locale defaults to latn numbering system instead of arab (Arabic-Indic digits)
"intl402/DateTimeFormat/prototype/format/temporal-objects-no-time-clip-non-latin-numerals.js",
- // Japanese era boundary resolution (Heisei/Showa month-day for PlainYearMonth reference day)
- "intl402/Temporal/PlainYearMonth/from/reference-day-japanese.js",
- // Leap year until - Hebrew calendar year boundary alignment
- "intl402/Temporal/PlainDate/prototype/until/leap-year-until.js",
- "intl402/Temporal/PlainDateTime/prototype/until/leap-year-until.js",
- "intl402/Temporal/ZonedDateTime/prototype/until/leap-year-until.js",
-
- // PlainMonthDay non-ISO calendar support needs more work
- // PlainMonthDay from - reference year selection, constrain-to-leap-day, and lunisolar dates
- "intl402/Temporal/PlainMonthDay/from/chinese-calendar-dates.js",
- "intl402/Temporal/PlainMonthDay/from/constrain-to-leap-day.js",
- "intl402/Temporal/PlainMonthDay/from/dangi-30-day-leap-months.js",
- "intl402/Temporal/PlainMonthDay/from/dangi-calendar-dates.js",
- "intl402/Temporal/PlainMonthDay/from/reference-date-noniso-calendar.js",
- "intl402/Temporal/PlainMonthDay/from/reference-year-1972.js",
-
- // PlainMonthDay monthCode - reference year selection affects month code for Chinese/Dangi
- "intl402/Temporal/PlainMonthDay/prototype/monthCode/chinese-calendar-dates.js",
- "intl402/Temporal/PlainMonthDay/prototype/monthCode/dangi-calendar-dates.js",
-
- // PlainYearMonth non-ISO calendar reference day and since
- "intl402/Temporal/PlainYearMonth/from/reference-day-chinese.js",
- "intl402/Temporal/PlainYearMonth/from/reference-day-hebrew.js",
- "intl402/Temporal/PlainYearMonth/prototype/since/chinese-calendar-dates.js",
- "intl402/Temporal/PlainYearMonth/prototype/since/dangi-calendar-dates.js",
-
- // === ANNEX B EXCLUSIONS ===
-
- // Acornima parser limitation: HTML-like comments () in dynamic Function() bodies/params
- // Requires parser option for HTML comments which Acornima doesn't support in function constructor context
- "annexB/built-ins/Function/createdynfn-html-close-comment-body.js",
- "annexB/built-ins/Function/createdynfn-html-close-comment-params.js",
- "annexB/built-ins/Function/createdynfn-html-open-comment-body.js",
- "annexB/built-ins/Function/createdynfn-html-open-comment-params.js",
- "annexB/built-ins/Function/createdynfn-no-line-terminator-html-close-comment-body.js",
-
- // Acornima parser limitation: assignment target type validation for call expressions
- // Per B.3.7, non-strict mode should allow CallExpression as assignment target in certain cases
- "annexB/language/expressions/assignmenttargettype/callexpression-as-for-in-lhs.js",
- "annexB/language/expressions/assignmenttargettype/callexpression-as-for-of-lhs.js",
- "annexB/language/expressions/assignmenttargettype/callexpression-in-compound-assignment.js",
- "annexB/language/expressions/assignmenttargettype/callexpression-in-postfix-update.js",
- "annexB/language/expressions/assignmenttargettype/callexpression-in-prefix-update.js",
- "annexB/language/expressions/assignmenttargettype/callexpression.js",
- "annexB/language/expressions/assignmenttargettype/cover-callexpression-and-asyncarrowhead.js",
-
- // Acornima parser limitation: for-in initializer in non-strict mode
- // Per B.3.6, `for (var x = expr in obj)` should be allowed in sloppy mode
- "annexB/language/statements/for-in/nonstrict-initializer.js",
-
- // Acornima parser/RegExp limitation: malformed named groups in non-unicode mode
- // Per B.1.2, non-unicode RegExp should accept some malformed named group syntax
- "annexB/built-ins/RegExp/named-groups/non-unicode-malformed.js",
-
- // Intl.Era-monthcode: remaining failures in era/calendar support
+ // Remaining intl402/Temporal calendar failures
"intl402/DateTimeFormat/prototype/formatToParts/compare-to-temporal-lunisolar.js",
"intl402/DateTimeFormat/prototype/formatToParts/compare-to-temporal.js",
"intl402/DateTimeFormat/prototype/formatToParts/era.js",
@@ -207,25 +153,17 @@
"intl402/Temporal/PlainDate/from/calendarresolvefields-error-ordering-chinese.js",
"intl402/Temporal/PlainDate/from/calendarresolvefields-error-ordering-gregory.js",
"intl402/Temporal/PlainDate/from/calendarresolvefields-error-ordering-japanese.js",
- "intl402/Temporal/PlainDate/from/canonicalize-era-codes-non-gregorian.js",
- "intl402/Temporal/PlainDate/from/era-boundary-japanese.js",
- "intl402/Temporal/PlainDate/from/era-japanese.js",
"intl402/Temporal/PlainDate/from/extreme-dates.js",
"intl402/Temporal/PlainDate/from/hebrew-keviah.js",
"intl402/Temporal/PlainDate/from/invalid-month-codes-hebrew.js",
- "intl402/Temporal/PlainDate/from/islamic-rgsa.js",
- "intl402/Temporal/PlainDate/from/islamic.js",
"intl402/Temporal/PlainDate/from/non-positive-single-era-year.js",
- "intl402/Temporal/PlainDate/from/roundtrip-from-iso.js",
"intl402/Temporal/PlainDate/from/roundtrip-from-property-bag.js",
"intl402/Temporal/PlainDate/from/roundtrip-from-string.js",
"intl402/Temporal/PlainDate/prototype/add/leap-months-hebrew.js",
"intl402/Temporal/PlainDate/prototype/add/leap-year-hebrew.js",
- "intl402/Temporal/PlainDate/prototype/dayOfYear/non-iso-calendar-basic.js",
"intl402/Temporal/PlainDate/prototype/daysInMonth/basic-islamic-umalqura.js",
"intl402/Temporal/PlainDate/prototype/daysInYear/basic-islamic-umalqura.js",
"intl402/Temporal/PlainDate/prototype/inLeapYear/basic-islamic-umalqura.js",
- "intl402/Temporal/PlainDate/prototype/since/era-boundary-japanese.js",
"intl402/Temporal/PlainDate/prototype/since/intercalary-month-coptic.js",
"intl402/Temporal/PlainDate/prototype/since/intercalary-month-ethioaa.js",
"intl402/Temporal/PlainDate/prototype/since/intercalary-month-ethiopic.js",
@@ -235,15 +173,14 @@
"intl402/Temporal/PlainDate/prototype/since/wrapping-at-end-of-month-hebrew.js",
"intl402/Temporal/PlainDate/prototype/subtract/leap-months-hebrew.js",
"intl402/Temporal/PlainDate/prototype/subtract/leap-year-hebrew.js",
- "intl402/Temporal/PlainDate/prototype/until/era-boundary-japanese.js",
"intl402/Temporal/PlainDate/prototype/until/intercalary-month-coptic.js",
"intl402/Temporal/PlainDate/prototype/until/intercalary-month-ethioaa.js",
"intl402/Temporal/PlainDate/prototype/until/intercalary-month-ethiopic.js",
"intl402/Temporal/PlainDate/prototype/until/leap-months-chinese.js",
"intl402/Temporal/PlainDate/prototype/until/leap-months-dangi.js",
"intl402/Temporal/PlainDate/prototype/until/leap-months-hebrew.js",
+ "intl402/Temporal/PlainDate/prototype/until/leap-year-until.js",
"intl402/Temporal/PlainDate/prototype/until/wrapping-at-end-of-month-hebrew.js",
- "intl402/Temporal/PlainDate/prototype/with/basic-coptic.js",
"intl402/Temporal/PlainDate/prototype/with/basic-islamic-umalqura.js",
"intl402/Temporal/PlainDate/prototype/with/leap-months-hebrew.js",
"intl402/Temporal/PlainDate/prototype/with/leap-year-hebrew.js",
@@ -251,23 +188,16 @@
"intl402/Temporal/PlainDate/prototype/year/arithmetic-year.js",
"intl402/Temporal/PlainDate/prototype/year/epoch-year.js",
"intl402/Temporal/PlainDateTime/from/calendarresolvefields-error-ordering-chinese.js",
- "intl402/Temporal/PlainDateTime/from/canonicalize-era-codes-non-gregorian.js",
- "intl402/Temporal/PlainDateTime/from/era-boundary-japanese.js",
- "intl402/Temporal/PlainDateTime/from/era-japanese.js",
"intl402/Temporal/PlainDateTime/from/extreme-dates.js",
"intl402/Temporal/PlainDateTime/from/invalid-month-codes-hebrew.js",
- "intl402/Temporal/PlainDateTime/from/islamic-rgsa.js",
- "intl402/Temporal/PlainDateTime/from/islamic.js",
"intl402/Temporal/PlainDateTime/from/non-positive-single-era-year.js",
"intl402/Temporal/PlainDateTime/from/roundtrip-from-property-bag.js",
"intl402/Temporal/PlainDateTime/from/roundtrip-from-string.js",
"intl402/Temporal/PlainDateTime/prototype/add/leap-months-hebrew.js",
"intl402/Temporal/PlainDateTime/prototype/add/leap-year-hebrew.js",
- "intl402/Temporal/PlainDateTime/prototype/dayOfYear/non-iso-calendar-basic.js",
"intl402/Temporal/PlainDateTime/prototype/daysInMonth/basic-islamic-umalqura.js",
"intl402/Temporal/PlainDateTime/prototype/daysInYear/basic-islamic-umalqura.js",
"intl402/Temporal/PlainDateTime/prototype/inLeapYear/basic-islamic-umalqura.js",
- "intl402/Temporal/PlainDateTime/prototype/since/era-boundary-japanese.js",
"intl402/Temporal/PlainDateTime/prototype/since/intercalary-month-coptic.js",
"intl402/Temporal/PlainDateTime/prototype/since/intercalary-month-ethioaa.js",
"intl402/Temporal/PlainDateTime/prototype/since/intercalary-month-ethiopic.js",
@@ -277,42 +207,17 @@
"intl402/Temporal/PlainDateTime/prototype/since/wrapping-at-end-of-month-hebrew.js",
"intl402/Temporal/PlainDateTime/prototype/subtract/leap-months-hebrew.js",
"intl402/Temporal/PlainDateTime/prototype/subtract/leap-year-hebrew.js",
- "intl402/Temporal/PlainDateTime/prototype/until/era-boundary-japanese.js",
"intl402/Temporal/PlainDateTime/prototype/until/intercalary-month-coptic.js",
"intl402/Temporal/PlainDateTime/prototype/until/intercalary-month-ethioaa.js",
"intl402/Temporal/PlainDateTime/prototype/until/intercalary-month-ethiopic.js",
"intl402/Temporal/PlainDateTime/prototype/until/leap-months-chinese.js",
"intl402/Temporal/PlainDateTime/prototype/until/leap-months-dangi.js",
"intl402/Temporal/PlainDateTime/prototype/until/leap-months-hebrew.js",
+ "intl402/Temporal/PlainDateTime/prototype/until/leap-year-until.js",
"intl402/Temporal/PlainDateTime/prototype/until/wrapping-at-end-of-month-hebrew.js",
- "intl402/Temporal/PlainDateTime/prototype/with/basic-buddhist.js",
- "intl402/Temporal/PlainDateTime/prototype/with/basic-coptic.js",
"intl402/Temporal/PlainDateTime/prototype/with/basic-islamic-umalqura.js",
- "intl402/Temporal/PlainDateTime/prototype/with/basic-roc.js",
- "intl402/Temporal/PlainDateTime/prototype/with/constrain-day-chinese.js",
- "intl402/Temporal/PlainDateTime/prototype/with/constrain-day-dangi.js",
- "intl402/Temporal/PlainDateTime/prototype/with/constrain-day-hebrew.js",
- "intl402/Temporal/PlainDateTime/prototype/with/constrain-day-indian.js",
- "intl402/Temporal/PlainDateTime/prototype/with/constrain-day-islamic-civil.js",
- "intl402/Temporal/PlainDateTime/prototype/with/constrain-day-islamic-tbla.js",
- "intl402/Temporal/PlainDateTime/prototype/with/constrain-day-persian.js",
"intl402/Temporal/PlainDateTime/prototype/with/leap-months-hebrew.js",
- "intl402/Temporal/PlainDateTime/prototype/with/leap-year-buddhist.js",
"intl402/Temporal/PlainDateTime/prototype/with/leap-year-hebrew.js",
- "intl402/Temporal/PlainDateTime/prototype/with/leap-year-roc.js",
- "intl402/Temporal/PlainDateTime/prototype/with/mutually-exclusive-fields-buddhist.js",
- "intl402/Temporal/PlainDateTime/prototype/with/mutually-exclusive-fields-chinese.js",
- "intl402/Temporal/PlainDateTime/prototype/with/mutually-exclusive-fields-coptic.js",
- "intl402/Temporal/PlainDateTime/prototype/with/mutually-exclusive-fields-dangi.js",
- "intl402/Temporal/PlainDateTime/prototype/with/mutually-exclusive-fields-ethioaa.js",
- "intl402/Temporal/PlainDateTime/prototype/with/mutually-exclusive-fields-ethiopic.js",
- "intl402/Temporal/PlainDateTime/prototype/with/mutually-exclusive-fields-hebrew.js",
- "intl402/Temporal/PlainDateTime/prototype/with/mutually-exclusive-fields-indian.js",
- "intl402/Temporal/PlainDateTime/prototype/with/mutually-exclusive-fields-islamic-civil.js",
- "intl402/Temporal/PlainDateTime/prototype/with/mutually-exclusive-fields-islamic-tbla.js",
- "intl402/Temporal/PlainDateTime/prototype/with/mutually-exclusive-fields-islamic-umalqura.js",
- "intl402/Temporal/PlainDateTime/prototype/with/mutually-exclusive-fields-persian.js",
- "intl402/Temporal/PlainDateTime/prototype/with/mutually-exclusive-fields-roc.js",
"intl402/Temporal/PlainDateTime/prototype/withCalendar/extreme-dates.js",
"intl402/Temporal/PlainDateTime/prototype/year/arithmetic-year.js",
"intl402/Temporal/PlainDateTime/prototype/year/epoch-year.js",
@@ -320,12 +225,16 @@
"intl402/Temporal/PlainMonthDay/from/calendarresolvefields-error-ordering-hebrew.js",
"intl402/Temporal/PlainMonthDay/from/calendarresolvefields-error-ordering-islamic.js",
"intl402/Temporal/PlainMonthDay/from/chinese-30-day-leap-months.js",
+ "intl402/Temporal/PlainMonthDay/from/chinese-calendar-dates.js",
"intl402/Temporal/PlainMonthDay/from/chinese-dangi-constrain-rare-leap-months.js",
"intl402/Temporal/PlainMonthDay/from/chinese-dangi-leap-month-with-year-from-options-bag-overflow-reject.js",
"intl402/Temporal/PlainMonthDay/from/chinese-dangi-leap-month-with-year-from-options-bag.js",
"intl402/Temporal/PlainMonthDay/from/chinese-leap-month-codes-common.js",
"intl402/Temporal/PlainMonthDay/from/chinese-month-codes.js",
+ "intl402/Temporal/PlainMonthDay/from/constrain-to-leap-day.js",
"intl402/Temporal/PlainMonthDay/from/coptic-invalid-month-code-m14.js",
+ "intl402/Temporal/PlainMonthDay/from/dangi-30-day-leap-months.js",
+ "intl402/Temporal/PlainMonthDay/from/dangi-calendar-dates.js",
"intl402/Temporal/PlainMonthDay/from/dangi-leap-month-codes-common.js",
"intl402/Temporal/PlainMonthDay/from/dangi-month-codes.js",
"intl402/Temporal/PlainMonthDay/from/dont-calculate-month-info-for-out-of-range-year.js",
@@ -337,25 +246,23 @@
"intl402/Temporal/PlainMonthDay/from/invalid-month-codes-hebrew.js",
"intl402/Temporal/PlainMonthDay/from/islamic-civil-invalid-month-code-m13.js",
"intl402/Temporal/PlainMonthDay/from/islamic-civil-month-codes.js",
- "intl402/Temporal/PlainMonthDay/from/islamic-rgsa.js",
"intl402/Temporal/PlainMonthDay/from/islamic-tbla-invalid-month-code-m13.js",
"intl402/Temporal/PlainMonthDay/from/islamic-tbla-month-codes.js",
"intl402/Temporal/PlainMonthDay/from/islamic-umalqura-invalid-month-code-m13.js",
"intl402/Temporal/PlainMonthDay/from/islamic-umalqura-month-codes.js",
- "intl402/Temporal/PlainMonthDay/from/islamic.js",
"intl402/Temporal/PlainMonthDay/from/persian-invalid-month-code-m13.js",
+ "intl402/Temporal/PlainMonthDay/from/reference-date-noniso-calendar.js",
+ "intl402/Temporal/PlainMonthDay/from/reference-year-1972.js",
+ "intl402/Temporal/PlainMonthDay/prototype/monthCode/chinese-calendar-dates.js",
+ "intl402/Temporal/PlainMonthDay/prototype/monthCode/dangi-calendar-dates.js",
"intl402/Temporal/PlainYearMonth/from/calendarresolvefields-error-ordering-chinese.js",
"intl402/Temporal/PlainYearMonth/from/calendarresolvefields-error-ordering-gregory.js",
"intl402/Temporal/PlainYearMonth/from/calendarresolvefields-error-ordering-japanese.js",
- "intl402/Temporal/PlainYearMonth/from/canonicalize-era-codes-non-gregorian.js",
- "intl402/Temporal/PlainYearMonth/from/era-boundary-japanese.js",
- "intl402/Temporal/PlainYearMonth/from/era-japanese.js",
"intl402/Temporal/PlainYearMonth/from/extreme-dates.js",
"intl402/Temporal/PlainYearMonth/from/extreme-unsupported-dates.js",
"intl402/Temporal/PlainYearMonth/from/invalid-month-codes-hebrew.js",
- "intl402/Temporal/PlainYearMonth/from/islamic-rgsa.js",
- "intl402/Temporal/PlainYearMonth/from/islamic.js",
"intl402/Temporal/PlainYearMonth/from/non-positive-single-era-year.js",
+ "intl402/Temporal/PlainYearMonth/from/reference-day-hebrew.js",
"intl402/Temporal/PlainYearMonth/from/roundtrip-from-property-bag.js",
"intl402/Temporal/PlainYearMonth/prototype/add/leap-months-hebrew.js",
"intl402/Temporal/PlainYearMonth/prototype/add/leap-year-hebrew.js",
@@ -373,10 +280,11 @@
"intl402/Temporal/PlainYearMonth/prototype/since/basic-islamic-tbla.js",
"intl402/Temporal/PlainYearMonth/prototype/since/basic-islamic-umalqura.js",
"intl402/Temporal/PlainYearMonth/prototype/since/basic-persian.js",
+ "intl402/Temporal/PlainYearMonth/prototype/since/chinese-calendar-dates.js",
+ "intl402/Temporal/PlainYearMonth/prototype/since/dangi-calendar-dates.js",
"intl402/Temporal/PlainYearMonth/prototype/since/era-boundary-islamic-civil.js",
"intl402/Temporal/PlainYearMonth/prototype/since/era-boundary-islamic-tbla.js",
"intl402/Temporal/PlainYearMonth/prototype/since/era-boundary-islamic-umalqura.js",
- "intl402/Temporal/PlainYearMonth/prototype/since/era-boundary-japanese.js",
"intl402/Temporal/PlainYearMonth/prototype/since/intercalary-month-coptic.js",
"intl402/Temporal/PlainYearMonth/prototype/since/intercalary-month-ethioaa.js",
"intl402/Temporal/PlainYearMonth/prototype/since/intercalary-month-ethiopic.js",
@@ -399,18 +307,13 @@
"intl402/Temporal/PlainYearMonth/prototype/until/era-boundary-islamic-civil.js",
"intl402/Temporal/PlainYearMonth/prototype/until/era-boundary-islamic-tbla.js",
"intl402/Temporal/PlainYearMonth/prototype/until/era-boundary-islamic-umalqura.js",
- "intl402/Temporal/PlainYearMonth/prototype/until/era-boundary-japanese.js",
"intl402/Temporal/PlainYearMonth/prototype/until/intercalary-month-coptic.js",
"intl402/Temporal/PlainYearMonth/prototype/until/intercalary-month-ethioaa.js",
"intl402/Temporal/PlainYearMonth/prototype/until/intercalary-month-ethiopic.js",
"intl402/Temporal/PlainYearMonth/prototype/until/leap-months-chinese.js",
"intl402/Temporal/PlainYearMonth/prototype/until/leap-months-dangi.js",
"intl402/Temporal/PlainYearMonth/prototype/until/leap-months-hebrew.js",
- "intl402/Temporal/PlainYearMonth/prototype/with/basic-buddhist.js",
- "intl402/Temporal/PlainYearMonth/prototype/with/basic-coptic.js",
- "intl402/Temporal/PlainYearMonth/prototype/with/basic-roc.js",
"intl402/Temporal/PlainYearMonth/prototype/with/leap-months-hebrew.js",
- "intl402/Temporal/PlainYearMonth/prototype/with/mutually-exclusive-fields-buddhist.js",
"intl402/Temporal/PlainYearMonth/prototype/with/mutually-exclusive-fields-chinese.js",
"intl402/Temporal/PlainYearMonth/prototype/with/mutually-exclusive-fields-coptic.js",
"intl402/Temporal/PlainYearMonth/prototype/with/mutually-exclusive-fields-dangi.js",
@@ -422,27 +325,19 @@
"intl402/Temporal/PlainYearMonth/prototype/with/mutually-exclusive-fields-islamic-tbla.js",
"intl402/Temporal/PlainYearMonth/prototype/with/mutually-exclusive-fields-islamic-umalqura.js",
"intl402/Temporal/PlainYearMonth/prototype/with/mutually-exclusive-fields-persian.js",
- "intl402/Temporal/PlainYearMonth/prototype/with/mutually-exclusive-fields-roc.js",
"intl402/Temporal/PlainYearMonth/prototype/year/arithmetic-year.js",
"intl402/Temporal/PlainYearMonth/prototype/year/epoch-year.js",
"intl402/Temporal/ZonedDateTime/from/calendarresolvefields-error-ordering-chinese.js",
- "intl402/Temporal/ZonedDateTime/from/canonicalize-era-codes-non-gregorian.js",
- "intl402/Temporal/ZonedDateTime/from/era-boundary-japanese.js",
- "intl402/Temporal/ZonedDateTime/from/era-japanese.js",
"intl402/Temporal/ZonedDateTime/from/extreme-dates.js",
"intl402/Temporal/ZonedDateTime/from/invalid-month-codes-hebrew.js",
- "intl402/Temporal/ZonedDateTime/from/islamic-rgsa.js",
- "intl402/Temporal/ZonedDateTime/from/islamic.js",
"intl402/Temporal/ZonedDateTime/from/non-positive-single-era-year.js",
"intl402/Temporal/ZonedDateTime/from/roundtrip-from-property-bag.js",
"intl402/Temporal/ZonedDateTime/from/roundtrip-from-string.js",
"intl402/Temporal/ZonedDateTime/prototype/add/leap-months-hebrew.js",
"intl402/Temporal/ZonedDateTime/prototype/add/leap-year-hebrew.js",
- "intl402/Temporal/ZonedDateTime/prototype/dayOfYear/non-iso-calendar-basic.js",
"intl402/Temporal/ZonedDateTime/prototype/daysInMonth/basic-islamic-umalqura.js",
"intl402/Temporal/ZonedDateTime/prototype/daysInYear/basic-islamic-umalqura.js",
"intl402/Temporal/ZonedDateTime/prototype/inLeapYear/basic-islamic-umalqura.js",
- "intl402/Temporal/ZonedDateTime/prototype/since/era-boundary-japanese.js",
"intl402/Temporal/ZonedDateTime/prototype/since/intercalary-month-coptic.js",
"intl402/Temporal/ZonedDateTime/prototype/since/intercalary-month-ethioaa.js",
"intl402/Temporal/ZonedDateTime/prototype/since/intercalary-month-ethiopic.js",
@@ -452,48 +347,48 @@
"intl402/Temporal/ZonedDateTime/prototype/since/wrapping-at-end-of-month-hebrew.js",
"intl402/Temporal/ZonedDateTime/prototype/subtract/leap-months-hebrew.js",
"intl402/Temporal/ZonedDateTime/prototype/subtract/leap-year-hebrew.js",
- "intl402/Temporal/ZonedDateTime/prototype/until/era-boundary-japanese.js",
"intl402/Temporal/ZonedDateTime/prototype/until/intercalary-month-coptic.js",
"intl402/Temporal/ZonedDateTime/prototype/until/intercalary-month-ethioaa.js",
"intl402/Temporal/ZonedDateTime/prototype/until/intercalary-month-ethiopic.js",
"intl402/Temporal/ZonedDateTime/prototype/until/leap-months-chinese.js",
"intl402/Temporal/ZonedDateTime/prototype/until/leap-months-dangi.js",
"intl402/Temporal/ZonedDateTime/prototype/until/leap-months-hebrew.js",
+ "intl402/Temporal/ZonedDateTime/prototype/until/leap-year-until.js",
"intl402/Temporal/ZonedDateTime/prototype/until/wrapping-at-end-of-month-hebrew.js",
- "intl402/Temporal/ZonedDateTime/prototype/with/basic-buddhist.js",
- "intl402/Temporal/ZonedDateTime/prototype/with/basic-coptic.js",
"intl402/Temporal/ZonedDateTime/prototype/with/basic-islamic-umalqura.js",
- "intl402/Temporal/ZonedDateTime/prototype/with/basic-roc.js",
- "intl402/Temporal/ZonedDateTime/prototype/with/calendarresolvefields-error-ordering-gregory.js",
- "intl402/Temporal/ZonedDateTime/prototype/with/calendarresolvefields-error-ordering-japanese.js",
- "intl402/Temporal/ZonedDateTime/prototype/with/constrain-day-chinese.js",
- "intl402/Temporal/ZonedDateTime/prototype/with/constrain-day-dangi.js",
- "intl402/Temporal/ZonedDateTime/prototype/with/constrain-day-hebrew.js",
- "intl402/Temporal/ZonedDateTime/prototype/with/constrain-day-indian.js",
- "intl402/Temporal/ZonedDateTime/prototype/with/constrain-day-islamic-civil.js",
- "intl402/Temporal/ZonedDateTime/prototype/with/constrain-day-islamic-tbla.js",
- "intl402/Temporal/ZonedDateTime/prototype/with/constrain-day-persian.js",
"intl402/Temporal/ZonedDateTime/prototype/with/leap-months-hebrew.js",
- "intl402/Temporal/ZonedDateTime/prototype/with/leap-year-buddhist.js",
"intl402/Temporal/ZonedDateTime/prototype/with/leap-year-hebrew.js",
- "intl402/Temporal/ZonedDateTime/prototype/with/leap-year-roc.js",
- "intl402/Temporal/ZonedDateTime/prototype/with/mutually-exclusive-fields-buddhist.js",
- "intl402/Temporal/ZonedDateTime/prototype/with/mutually-exclusive-fields-chinese.js",
- "intl402/Temporal/ZonedDateTime/prototype/with/mutually-exclusive-fields-coptic.js",
- "intl402/Temporal/ZonedDateTime/prototype/with/mutually-exclusive-fields-dangi.js",
- "intl402/Temporal/ZonedDateTime/prototype/with/mutually-exclusive-fields-ethioaa.js",
- "intl402/Temporal/ZonedDateTime/prototype/with/mutually-exclusive-fields-ethiopic.js",
- "intl402/Temporal/ZonedDateTime/prototype/with/mutually-exclusive-fields-gregory.js",
- "intl402/Temporal/ZonedDateTime/prototype/with/mutually-exclusive-fields-hebrew.js",
- "intl402/Temporal/ZonedDateTime/prototype/with/mutually-exclusive-fields-indian.js",
- "intl402/Temporal/ZonedDateTime/prototype/with/mutually-exclusive-fields-islamic-civil.js",
- "intl402/Temporal/ZonedDateTime/prototype/with/mutually-exclusive-fields-islamic-tbla.js",
- "intl402/Temporal/ZonedDateTime/prototype/with/mutually-exclusive-fields-islamic-umalqura.js",
- "intl402/Temporal/ZonedDateTime/prototype/with/mutually-exclusive-fields-persian.js",
- "intl402/Temporal/ZonedDateTime/prototype/with/mutually-exclusive-fields-roc.js",
"intl402/Temporal/ZonedDateTime/prototype/withCalendar/extreme-dates.js",
"intl402/Temporal/ZonedDateTime/prototype/year/arithmetic-year.js",
- "intl402/Temporal/ZonedDateTime/prototype/year/epoch-year.js"
+ "intl402/Temporal/ZonedDateTime/prototype/year/epoch-year.js",
+
+ // === ANNEX B EXCLUSIONS ===
+
+ // Acornima parser limitation: HTML-like comments () in dynamic Function() bodies/params
+ // Requires parser option for HTML comments which Acornima doesn't support in function constructor context
+ "annexB/built-ins/Function/createdynfn-html-close-comment-body.js",
+ "annexB/built-ins/Function/createdynfn-html-close-comment-params.js",
+ "annexB/built-ins/Function/createdynfn-html-open-comment-body.js",
+ "annexB/built-ins/Function/createdynfn-html-open-comment-params.js",
+ "annexB/built-ins/Function/createdynfn-no-line-terminator-html-close-comment-body.js",
+
+ // Acornima parser limitation: assignment target type validation for call expressions
+ // Per B.3.7, non-strict mode should allow CallExpression as assignment target in certain cases
+ "annexB/language/expressions/assignmenttargettype/callexpression-as-for-in-lhs.js",
+ "annexB/language/expressions/assignmenttargettype/callexpression-as-for-of-lhs.js",
+ "annexB/language/expressions/assignmenttargettype/callexpression-in-compound-assignment.js",
+ "annexB/language/expressions/assignmenttargettype/callexpression-in-postfix-update.js",
+ "annexB/language/expressions/assignmenttargettype/callexpression-in-prefix-update.js",
+ "annexB/language/expressions/assignmenttargettype/callexpression.js",
+ "annexB/language/expressions/assignmenttargettype/cover-callexpression-and-asyncarrowhead.js",
+
+ // Acornima parser limitation: for-in initializer in non-strict mode
+ // Per B.3.6, `for (var x = expr in obj)` should be allowed in sloppy mode
+ "annexB/language/statements/for-in/nonstrict-initializer.js",
+
+ // Acornima parser/RegExp limitation: malformed named groups in non-unicode mode
+ // Per B.1.2, non-unicode RegExp should accept some malformed named group syntax
+ "annexB/built-ins/RegExp/named-groups/non-unicode-malformed.js"
]
}
diff --git a/Jint/Native/Temporal/NonIsoCalendars.cs b/Jint/Native/Temporal/NonIsoCalendars.cs
index d9ab4c838c..4bf668c7c4 100644
--- a/Jint/Native/Temporal/NonIsoCalendars.cs
+++ b/Jint/Native/Temporal/NonIsoCalendars.cs
@@ -408,13 +408,15 @@ internal static DurationRecord CalendarDateUntil(string calendar, in IsoDate one
{
return calendar switch
{
+ // Single-era calendars: always use the primary era
"hebrew" => "am",
"persian" => "ap",
- "chinese" or "dangi" => null, // no eras
- "coptic" => calDate.Year >= 1 ? "am" : "bd",
- "ethiopic" => calDate.Year >= 1 ? "am" : "aa",
+ "coptic" => "am",
"ethioaa" => "aa",
"indian" => "shaka",
+ "chinese" or "dangi" => null, // no eras
+ // Multi-era calendars: era depends on year
+ "ethiopic" => calDate.Year >= 1 ? "am" : "aa",
"islamic-umalqura" or "islamic-civil" or "islamic-tbla" => calDate.Year >= 1 ? "ah" : "bh",
_ => null
};
@@ -427,13 +429,15 @@ internal static DurationRecord CalendarDateUntil(string calendar, in IsoDate one
{
return calendar switch
{
+ // Single-era calendars: eraYear = year directly
"hebrew" => calDate.Year,
"persian" => calDate.Year,
- "chinese" or "dangi" => null, // no eras
- "coptic" => calDate.Year >= 1 ? calDate.Year : 1 - calDate.Year,
- "ethiopic" => calDate.Year >= 1 ? calDate.Year : calDate.Year + 5500,
+ "coptic" => calDate.Year,
"ethioaa" => calDate.Year,
"indian" => calDate.Year,
+ "chinese" or "dangi" => null, // no eras
+ // Multi-era calendars: eraYear depends on year
+ "ethiopic" => calDate.Year >= 1 ? calDate.Year : calDate.Year + 5500,
"islamic-umalqura" or "islamic-civil" or "islamic-tbla" => calDate.Year >= 1 ? calDate.Year : 1 - calDate.Year,
_ => null
};
@@ -450,34 +454,26 @@ internal static int MonthCodeToOrdinal(string calendar, Calendar? cal, int year,
if (calendar is "persian" or "indian" or "islamic-umalqura" or "islamic-civil" or "islamic-tbla")
{
- // These calendars have no leap months
- if (isLeap)
+ // These calendars have 12 months and no leap months
+ // Invalid monthCode (M13+, M00, or any leap month) is always rejected
+ if (isLeap || displayMonth < 1 || displayMonth > 12)
{
- if (string.Equals(overflow, "reject", StringComparison.Ordinal))
- {
- throw new InvalidOperationException("reject");
- }
-
- // Constrain: use the base month
+ throw new InvalidOperationException("reject");
}
- return Clamp(displayMonth, 1, 12);
+ return displayMonth;
}
if (calendar is "coptic" or "ethiopic" or "ethioaa")
{
// 13-month calendars with no leap months
- if (isLeap)
+ // Invalid monthCode (M14+, M00, or any leap month) is always rejected
+ if (isLeap || displayMonth < 1 || displayMonth > 13)
{
- if (string.Equals(overflow, "reject", StringComparison.Ordinal))
- {
- throw new InvalidOperationException("reject");
- }
-
- // Constrain: use the base month
+ throw new InvalidOperationException("reject");
}
- return Clamp(displayMonth, 1, 13);
+ return displayMonth;
}
var leapOrdinal = GetLeapMonthOrdinal(calendar, cal, year);
diff --git a/Jint/Native/Temporal/PlainDate/PlainDateConstructor.cs b/Jint/Native/Temporal/PlainDate/PlainDateConstructor.cs
index 62f3672b62..7c97720006 100644
--- a/Jint/Native/Temporal/PlainDate/PlainDateConstructor.cs
+++ b/Jint/Native/Temporal/PlainDate/PlainDateConstructor.cs
@@ -102,6 +102,8 @@ private JsPlainDate ToTemporalDateFromObjectWithOptions(ObjectInstance obj, JsVa
calendar = TemporalHelpers.ToTemporalCalendarIdentifier(_realm, calendarValue);
}
+ TemporalHelpers.RejectTemporalUnsupportedCalendar(_realm, calendar);
+
// 2. day - read and convert immediately
var dayValue = obj.Get("day");
if (dayValue.IsUndefined())
diff --git a/Jint/Native/Temporal/PlainDate/PlainDatePrototype.cs b/Jint/Native/Temporal/PlainDate/PlainDatePrototype.cs
index ff6dda6ede..f64e644d8e 100644
--- a/Jint/Native/Temporal/PlainDate/PlainDatePrototype.cs
+++ b/Jint/Native/Temporal/PlainDate/PlainDatePrototype.cs
@@ -120,7 +120,11 @@ private JsNumber GetDay(JsValue thisObject, JsCallArguments arguments)
return JsNumber.Create(TemporalHelpers.CalendarDay(pd.Calendar, pd.IsoDate));
}
private JsNumber GetDayOfWeek(JsValue thisObject, JsCallArguments arguments) => JsNumber.Create(ValidatePlainDate(thisObject).IsoDate.DayOfWeek());
- private JsNumber GetDayOfYear(JsValue thisObject, JsCallArguments arguments) => JsNumber.Create(ValidatePlainDate(thisObject).IsoDate.DayOfYear());
+ private JsNumber GetDayOfYear(JsValue thisObject, JsCallArguments arguments)
+ {
+ var pd = ValidatePlainDate(thisObject);
+ return JsNumber.Create(TemporalHelpers.CalendarDayOfYear(pd.Calendar, pd.IsoDate));
+ }
private JsValue GetWeekOfYear(JsValue thisObject, JsCallArguments arguments)
{
var pd = ValidatePlainDate(thisObject);
@@ -338,20 +342,10 @@ private JsPlainDate With(JsValue thisObject, JsCallArguments arguments)
var calMonth = month ?? plainDate.IsoDate.Month;
var calDay = day ?? plainDate.IsoDate.Day;
- if (monthCode is not null)
+ var mc = TemporalHelpers.ValidateMonthCodeForNonLeapCalendar(_realm, monthCode, month);
+ if (mc.HasValue)
{
- var mc = TemporalHelpers.ParseMonthCode(_realm, monthCode);
- if (monthCode.Length == 4 && monthCode[3] == 'L')
- {
- Throw.RangeError(_realm, $"Leap months are not valid for calendar: {monthCode}");
- }
-
- if (month.HasValue && month.Value != mc)
- {
- Throw.RangeError(_realm, "month and monthCode must match");
- }
-
- calMonth = mc;
+ calMonth = mc.Value;
}
var date2 = TemporalHelpers.CalendarDateToISO(_realm, plainDate.Calendar, calYear, calMonth, calDay, overflow);
@@ -368,28 +362,8 @@ private JsPlainDate With(JsValue thisObject, JsCallArguments arguments)
var finalMonth = month ?? plainDate.IsoDate.Month;
var finalDayVal = day ?? plainDate.IsoDate.Day;
- // Handle monthCode - if provided, validate and use it
- int? parsedMonthCode = null;
- if (monthCode is not null)
- {
- parsedMonthCode = TemporalHelpers.ParseMonthCode(_realm, monthCode);
-
- if (monthCode.Length == 4 && monthCode[3] == 'L')
- {
- Throw.RangeError(_realm, $"Leap months are not valid for ISO 8601 calendar: {monthCode}");
- }
-
- if (parsedMonthCode.Value < 1 || parsedMonthCode.Value > 12)
- {
- Throw.RangeError(_realm, $"Month {parsedMonthCode.Value} is not valid for ISO 8601 calendar");
- }
- }
-
- if (month.HasValue && parsedMonthCode.HasValue && month.Value != parsedMonthCode.Value)
- {
- Throw.RangeError(_realm, "month and monthCode must match");
- }
-
+ // Handle monthCode - validate and use it
+ var parsedMonthCode = TemporalHelpers.ValidateMonthCodeForNonLeapCalendar(_realm, monthCode, month);
if (parsedMonthCode.HasValue)
{
finalMonth = parsedMonthCode.Value;
diff --git a/Jint/Native/Temporal/PlainDateTime/PlainDateTimeConstructor.cs b/Jint/Native/Temporal/PlainDateTime/PlainDateTimeConstructor.cs
index 27ac313543..eac7be56f6 100644
--- a/Jint/Native/Temporal/PlainDateTime/PlainDateTimeConstructor.cs
+++ b/Jint/Native/Temporal/PlainDateTime/PlainDateTimeConstructor.cs
@@ -252,6 +252,8 @@ private JsPlainDateTime ToTemporalDateTimeFromFields(ObjectInstance obj, JsValue
calendar = TemporalHelpers.ToTemporalCalendarIdentifier(_realm, calendarProp);
}
+ TemporalHelpers.RejectTemporalUnsupportedCalendar(_realm, calendar);
+
// 2. day - read and convert immediately
var dayValue = obj.Get("day");
if (dayValue.IsUndefined())
diff --git a/Jint/Native/Temporal/PlainDateTime/PlainDateTimePrototype.cs b/Jint/Native/Temporal/PlainDateTime/PlainDateTimePrototype.cs
index 6f42854344..0db1bba97f 100644
--- a/Jint/Native/Temporal/PlainDateTime/PlainDateTimePrototype.cs
+++ b/Jint/Native/Temporal/PlainDateTime/PlainDateTimePrototype.cs
@@ -134,7 +134,11 @@ private JsNumber GetDay(JsValue thisObject, JsCallArguments arguments)
private JsNumber GetMicrosecond(JsValue thisObject, JsCallArguments arguments) => JsNumber.Create(ValidatePlainDateTime(thisObject).IsoDateTime.Microsecond);
private JsNumber GetNanosecond(JsValue thisObject, JsCallArguments arguments) => JsNumber.Create(ValidatePlainDateTime(thisObject).IsoDateTime.Nanosecond);
private JsNumber GetDayOfWeek(JsValue thisObject, JsCallArguments arguments) => JsNumber.Create(ValidatePlainDateTime(thisObject).IsoDateTime.Date.DayOfWeek());
- private JsNumber GetDayOfYear(JsValue thisObject, JsCallArguments arguments) => JsNumber.Create(ValidatePlainDateTime(thisObject).IsoDateTime.Date.DayOfYear());
+ private JsNumber GetDayOfYear(JsValue thisObject, JsCallArguments arguments)
+ {
+ var pdt = ValidatePlainDateTime(thisObject);
+ return JsNumber.Create(TemporalHelpers.CalendarDayOfYear(pdt.Calendar, pdt.IsoDateTime.Date));
+ }
private JsValue GetWeekOfYear(JsValue thisObject, JsCallArguments arguments)
{
var pdt = ValidatePlainDateTime(thisObject);
@@ -221,6 +225,8 @@ private JsPlainDateTime With(JsValue thisObject, JsCallArguments arguments)
var any = false;
JsValue v;
+ var isNonIso8601 = plainDateTime.Calendar is not "iso8601" and not "gregory";
+
v = obj.Get("day");
int day;
if (!v.IsUndefined())
@@ -230,7 +236,7 @@ private JsPlainDateTime With(JsValue thisObject, JsCallArguments arguments)
}
else
{
- day = NonIsoCalendars.IsNonIsoCalendar(plainDateTime.Calendar)
+ day = isNonIso8601
? TemporalHelpers.CalendarDay(plainDateTime.Calendar, plainDateTime.IsoDateTime.Date)
: plainDateTime.IsoDateTime.Day;
}
@@ -282,7 +288,7 @@ private JsPlainDateTime With(JsValue thisObject, JsCallArguments arguments)
}
else
{
- month = NonIsoCalendars.IsNonIsoCalendar(plainDateTime.Calendar)
+ month = isNonIso8601
? TemporalHelpers.CalendarMonth(plainDateTime.Calendar, plainDateTime.IsoDateTime.Date)
: plainDateTime.IsoDateTime.Month;
}
@@ -294,7 +300,7 @@ private JsPlainDateTime With(JsValue thisObject, JsCallArguments arguments)
any = true;
monthCode = TypeConverter.ToString(v);
}
- else if (NonIsoCalendars.IsNonIsoCalendar(plainDateTime.Calendar) && !monthExplicit)
+ else if (isNonIso8601 && !monthExplicit)
{
monthCode = TemporalHelpers.CalendarMonthCode(plainDateTime.Calendar, plainDateTime.IsoDateTime.Date);
}
@@ -326,7 +332,7 @@ private JsPlainDateTime With(JsValue thisObject, JsCallArguments arguments)
}
else
{
- year = NonIsoCalendars.IsNonIsoCalendar(plainDateTime.Calendar)
+ year = isNonIso8601
? TemporalHelpers.CalendarYear(plainDateTime.Calendar, plainDateTime.IsoDateTime.Date)
: plainDateTime.IsoDateTime.Year;
}
@@ -365,41 +371,32 @@ private JsPlainDateTime With(JsValue thisObject, JsCallArguments arguments)
// Process monthCode (after reading options, before algorithmic validation)
int? monthFromCode = null;
- if (monthCode is not null)
+ if (!isNonIso8601 || TemporalHelpers.IsGregorianBasedCalendar(plainDateTime.Calendar))
{
- // Use ParseMonthCode which properly handles "L" suffix for leap months
- monthFromCode = TemporalHelpers.ParseMonthCode(_realm, monthCode);
+ // ISO/Gregorian-based: validate no leap months, month/monthCode consistency
+ monthFromCode = TemporalHelpers.ValidateMonthCodeForNonLeapCalendar(
+ _realm, monthCode, monthExplicit ? month : null);
- // ISO/Gregorian calendars don't support leap months
- if (!NonIsoCalendars.IsNonIsoCalendar(plainDateTime.Calendar))
+ if (monthFromCode.HasValue)
{
- if (monthCode.Length == 4 && monthCode[3] == 'L')
- {
- Throw.RangeError(_realm, $"Leap months are not valid for calendar: {monthCode}");
- }
-
- if (monthFromCode.Value < 1 || monthFromCode.Value > 12)
- {
- Throw.RangeError(_realm, $"Month {monthFromCode.Value} is not valid for calendar");
- }
+ month = monthFromCode.Value;
}
}
-
- // Validate month/monthCode consistency (ISO calendars only - non-ISO ordinal ≠ display)
- if (!NonIsoCalendars.IsNonIsoCalendar(plainDateTime.Calendar) &&
- monthFromCode.HasValue && month != plainDateTime.IsoDateTime.Month && month != monthFromCode.Value)
+ else if (monthCode is not null)
{
- Throw.RangeError(_realm, "month and monthCode must match");
- }
+ // Non-ISO: just parse for well-formedness, let CalendarDateToISO handle validation
+ monthFromCode = TemporalHelpers.ParseMonthCode(_realm, monthCode);
- // Use monthCode if provided (for ISO calendars)
- if (monthFromCode.HasValue && !NonIsoCalendars.IsNonIsoCalendar(plainDateTime.Calendar))
- {
- month = monthFromCode.Value;
+ // When monthCode is explicitly provided but month is not, signal CalendarDateToIso
+ // to use monthCode by passing month=0 (avoids month/monthCode mismatch rejection)
+ if (!monthExplicit)
+ {
+ month = 0;
+ }
}
IsoDate? date;
- if (NonIsoCalendars.IsNonIsoCalendar(plainDateTime.Calendar))
+ if (isNonIso8601)
{
date = TemporalHelpers.CalendarDateToISO(_realm, plainDateTime.Calendar, year, month, day, overflow, monthCode);
}
diff --git a/Jint/Native/Temporal/PlainMonthDay/PlainMonthDayConstructor.cs b/Jint/Native/Temporal/PlainMonthDay/PlainMonthDayConstructor.cs
index a57cf0afa2..1a0a25929d 100644
--- a/Jint/Native/Temporal/PlainMonthDay/PlainMonthDayConstructor.cs
+++ b/Jint/Native/Temporal/PlainMonthDay/PlainMonthDayConstructor.cs
@@ -195,6 +195,8 @@ private JsPlainMonthDay ToTemporalMonthDayFromFields(ObjectInstance obj, JsValue
calendar = TemporalHelpers.ToTemporalCalendarIdentifier(_realm, calendarValue);
}
+ TemporalHelpers.RejectTemporalUnsupportedCalendar(_realm, calendar);
+
// 2. day - read and convert immediately
var dayValue = obj.Get("day");
if (dayValue.IsUndefined())
diff --git a/Jint/Native/Temporal/PlainMonthDay/PlainMonthDayPrototype.cs b/Jint/Native/Temporal/PlainMonthDay/PlainMonthDayPrototype.cs
index 250a703315..c0369ece39 100644
--- a/Jint/Native/Temporal/PlainMonthDay/PlainMonthDayPrototype.cs
+++ b/Jint/Native/Temporal/PlainMonthDay/PlainMonthDayPrototype.cs
@@ -182,35 +182,20 @@ private JsPlainMonthDay With(JsValue thisObject, JsCallArguments arguments)
// NOW validate monthCode (after options are read)
int? monthFromCode = null;
- if (monthCode is not null)
+ if (!isNonIso)
{
- monthFromCode = TemporalHelpers.ParseMonthCode(_realm, monthCode);
+ // ISO/Gregorian: validate no leap months, month/monthCode consistency
+ monthFromCode = TemporalHelpers.ValidateMonthCodeForNonLeapCalendar(
+ _realm, monthCode, !monthProp.IsUndefined() ? month : null);
- // For ISO/Gregorian calendars: validate monthCode is valid (01-12, no leap months)
- if (!isNonIso)
+ if (monthFromCode.HasValue)
{
- if (monthCode.Length == 4 && monthCode[3] == 'L')
- {
- Throw.RangeError(_realm, $"Leap months are not valid for calendar: {monthCode}");
- }
-
- if (monthFromCode.Value < 1 || monthFromCode.Value > 12)
- {
- Throw.RangeError(_realm, $"Month {monthFromCode.Value} is not valid for calendar");
- }
+ month = monthFromCode.Value;
}
}
-
- // Validate month/monthCode consistency (ISO only)
- if (!isNonIso && monthFromCode.HasValue && !monthProp.IsUndefined() && month != monthFromCode.Value)
+ else if (monthCode is not null)
{
- Throw.RangeError(_realm, "month and monthCode must match");
- }
-
- // Use monthCode if provided (ISO only - non-ISO handled by CalendarDateToISO)
- if (!isNonIso && monthFromCode.HasValue)
- {
- month = monthFromCode.Value;
+ monthFromCode = TemporalHelpers.ParseMonthCode(_realm, monthCode);
}
if (isNonIso)
diff --git a/Jint/Native/Temporal/PlainYearMonth/PlainYearMonthConstructor.cs b/Jint/Native/Temporal/PlainYearMonth/PlainYearMonthConstructor.cs
index 0d4669b2ce..0665323512 100644
--- a/Jint/Native/Temporal/PlainYearMonth/PlainYearMonthConstructor.cs
+++ b/Jint/Native/Temporal/PlainYearMonth/PlainYearMonthConstructor.cs
@@ -234,6 +234,8 @@ private JsPlainYearMonth ToTemporalYearMonthFromObjectWithOptions(ObjectInstance
calendar = TemporalHelpers.ToTemporalCalendarIdentifier(_realm, calendarValue);
}
+ TemporalHelpers.RejectTemporalUnsupportedCalendar(_realm, calendar);
+
// 2. era/eraYear - read for era-supporting calendars (alphabetically between calendar and month)
var eraYear = TemporalHelpers.ReadEraFields(_realm, obj, calendar);
diff --git a/Jint/Native/Temporal/PlainYearMonth/PlainYearMonthPrototype.cs b/Jint/Native/Temporal/PlainYearMonth/PlainYearMonthPrototype.cs
index 52f31a684a..b307fed75a 100644
--- a/Jint/Native/Temporal/PlainYearMonth/PlainYearMonthPrototype.cs
+++ b/Jint/Native/Temporal/PlainYearMonth/PlainYearMonthPrototype.cs
@@ -158,7 +158,7 @@ private JsPlainYearMonth With(JsValue thisObject, JsCallArguments arguments)
// Read and convert properties in alphabetical order with immediate conversion per spec
// Order: month, monthCode, year
- var isNonIso = NonIsoCalendars.IsNonIsoCalendar(ym.Calendar);
+ var isNonIso8601 = ym.Calendar is not "iso8601" and not "gregory";
var monthProp = obj.Get("month");
int month;
@@ -168,7 +168,7 @@ private JsPlainYearMonth With(JsValue thisObject, JsCallArguments arguments)
}
else
{
- month = isNonIso
+ month = isNonIso8601
? TemporalHelpers.CalendarMonth(ym.Calendar, ym.IsoDate)
: ym.IsoDate.Month;
}
@@ -202,7 +202,7 @@ private JsPlainYearMonth With(JsValue thisObject, JsCallArguments arguments)
monthCode = TypeConverter.ToString(monthCodeProp);
}
}
- else if (isNonIso && monthProp.IsUndefined())
+ else if (isNonIso8601 && monthProp.IsUndefined())
{
// Only default monthCode from the calendar when month was not explicitly provided;
// if the user set month explicitly, let month drive the conversion without monthCode
@@ -217,7 +217,7 @@ private JsPlainYearMonth With(JsValue thisObject, JsCallArguments arguments)
}
else
{
- year = isNonIso
+ year = isNonIso8601
? TemporalHelpers.CalendarYear(ym.Calendar, ym.IsoDate)
: ym.IsoDate.Year;
}
@@ -254,13 +254,36 @@ private JsPlainYearMonth With(JsValue thisObject, JsCallArguments arguments)
// Read options BEFORE any validation (per spec)
var overflow = TemporalHelpers.GetOverflowOption(_realm, options);
- // Handle non-ISO calendars via CalendarDateToISO
- if (isNonIso)
+ // Handle non-ISO8601 calendars via CalendarDateToISO
+ if (isNonIso8601)
{
// Validate monthCode well-formedness if explicitly provided
if (!monthCodeProp.IsUndefined() && monthCode is not null)
{
- TemporalHelpers.ParseMonthCode(_realm, monthCode);
+ var mc = TemporalHelpers.ParseMonthCode(_realm, monthCode);
+
+ // Gregorian-based calendars don't support leap months
+ if (TemporalHelpers.IsGregorianBasedCalendar(ym.Calendar))
+ {
+ if (monthCode.Length == 4 && monthCode[3] == 'L')
+ {
+ Throw.RangeError(_realm, $"Leap months are not valid for calendar: {monthCode}");
+ }
+
+ if (mc < 1 || mc > 12)
+ {
+ Throw.RangeError(_realm, $"Month {mc} is not valid for calendar");
+ }
+
+ // month/monthCode consistency for Gregorian-based
+ if (!monthProp.IsUndefined() && month != mc)
+ {
+ Throw.RangeError(_realm, "month and monthCode must match");
+ }
+
+ month = mc;
+ monthCode = null; // let month drive for Gregorian-based
+ }
}
var date = TemporalHelpers.CalendarDateToISO(_realm, ym.Calendar, year, month, 1, overflow, monthCode);
@@ -277,31 +300,9 @@ private JsPlainYearMonth With(JsValue thisObject, JsCallArguments arguments)
return _constructor.Construct(date.Value, ym.Calendar);
}
- // ISO calendar path
- int? parsedMonthFromCode = null;
- if (monthCode is not null)
- {
- // Use ParseMonthCode for proper validation (well-formedness and range)
- parsedMonthFromCode = TemporalHelpers.ParseMonthCode(_realm, monthCode);
-
- // For ISO 8601 calendar: validate monthCode is valid (01-12, no leap months)
- if (monthCode.Length == 4 && monthCode[3] == 'L')
- {
- Throw.RangeError(_realm, $"Leap months are not valid for ISO 8601 calendar: {monthCode}");
- }
- if (parsedMonthFromCode.Value < 1 || parsedMonthFromCode.Value > 12)
- {
- Throw.RangeError(_realm, $"Month {parsedMonthFromCode.Value} is not valid for ISO 8601 calendar");
- }
- }
-
- // Validate month/monthCode consistency
- if (parsedMonthFromCode.HasValue && !monthProp.IsUndefined() && month != parsedMonthFromCode.Value)
- {
- Throw.RangeError(_realm, "month and monthCode must match");
- }
-
- // Use monthCode if provided
+ // ISO calendar path - validate monthCode
+ var parsedMonthFromCode = TemporalHelpers.ValidateMonthCodeForNonLeapCalendar(
+ _realm, monthCode, !monthProp.IsUndefined() ? month : null);
if (parsedMonthFromCode.HasValue)
{
month = parsedMonthFromCode.Value;
diff --git a/Jint/Native/Temporal/TemporalHelpers.cs b/Jint/Native/Temporal/TemporalHelpers.cs
index 455f46533a..17d8dd0836 100644
--- a/Jint/Native/Temporal/TemporalHelpers.cs
+++ b/Jint/Native/Temporal/TemporalHelpers.cs
@@ -1607,6 +1607,50 @@ public static bool ISOYearMonthWithinLimits(int year, int month)
};
}
+ ///
+ /// Throws RangeError for observation-based calendars that cannot be used in Temporal.
+ /// "islamic" and "islamic-rgsa" are only valid for Intl.DateTimeFormat, not Temporal.
+ ///
+ internal static void RejectTemporalUnsupportedCalendar(Realm realm, string calendar)
+ {
+ if (calendar is "islamic" or "islamic-rgsa")
+ {
+ Throw.RangeError(realm, $"Calendar '{calendar}' is not supported for Temporal operations");
+ }
+ }
+
+ ///
+ /// Validates a monthCode for calendars that don't support leap months (ISO, Gregorian-based).
+ /// Also validates month/monthCode consistency when both are provided.
+ /// Returns the parsed month number from the monthCode, or null if no monthCode.
+ ///
+ internal static int? ValidateMonthCodeForNonLeapCalendar(Realm realm, string? monthCode, int? explicitMonth)
+ {
+ if (monthCode is null)
+ {
+ return null;
+ }
+
+ var parsed = ParseMonthCode(realm, monthCode);
+
+ if (monthCode.Length == 4 && monthCode[3] == 'L')
+ {
+ Throw.RangeError(realm, $"Leap months are not valid for calendar: {monthCode}");
+ }
+
+ if (parsed < 1 || parsed > 12)
+ {
+ Throw.RangeError(realm, $"Month {parsed} is not valid for calendar");
+ }
+
+ if (explicitMonth.HasValue && explicitMonth.Value != parsed)
+ {
+ Throw.RangeError(realm, "month and monthCode must match");
+ }
+
+ return parsed;
+ }
+
///
/// Converts calendar-system year/month/day to ISO year/month/day.
/// For non-ISO calendars, the input fields are in the calendar's system
@@ -1614,6 +1658,13 @@ public static bool ISOYearMonthWithinLimits(int year, int month)
///
public static IsoDate? CalendarDateToISO(Realm realm, string calendar, int year, int month, int day, string overflow, string? monthCode = null)
{
+ // Observation-based calendars cannot be used for Temporal arithmetic
+ if (calendar is "islamic" or "islamic-rgsa")
+ {
+ Throw.RangeError(realm, $"Calendar '{calendar}' is not supported for Temporal operations");
+ return null;
+ }
+
if (calendar is "iso8601" or "gregory")
{
return RegulateIsoDate(year, month, day, overflow);
@@ -1849,7 +1900,6 @@ internal static bool CalendarUsesEras(string calendar)
case "buddhist":
return "be";
case "japanese":
- // Temporal uses 1873 as Meiji start (when Japan adopted Gregorian calendar)
if (isoYear >= 2019) return "reiwa";
if (isoYear >= 1989) return "heisei";
if (isoYear >= 1926) return "showa";
@@ -1980,6 +2030,32 @@ internal static int CalendarDay(string calendar, in IsoDate isoDate)
return isoDate.Day;
}
+ ///
+ /// Returns the day of the year in the calendar system for the given ISO date.
+ ///
+ internal static int CalendarDayOfYear(string calendar, in IsoDate isoDate)
+ {
+ if (IsGregorianBasedCalendar(calendar))
+ {
+ return isoDate.DayOfYear();
+ }
+
+ if (NonIsoCalendars.IsNonIsoCalendar(calendar))
+ {
+ var calDate = NonIsoCalendars.IsoToCalendarDate(calendar, isoDate);
+ // Find the first day of the calendar year
+ var firstDay = NonIsoCalendars.CalendarDateToIso(calendar, calDate.Year, "M01", 0, 1, "constrain");
+ if (firstDay is not null)
+ {
+ var epochThis = IsoDateToDays(isoDate.Year, isoDate.Month, isoDate.Day);
+ var epochFirst = IsoDateToDays(firstDay.Value.Year, firstDay.Value.Month, firstDay.Value.Day);
+ return (int) (epochThis - epochFirst) + 1;
+ }
+ }
+
+ return isoDate.DayOfYear();
+ }
+
///
/// Returns the number of days in the calendar month containing the given ISO date.
///
@@ -2117,8 +2193,8 @@ private static string JapaneseEra(in IsoDate d)
if (y > 1926 || (y == 1926 && m == 12 && day >= 25)) return "showa";
// Taisho: July 30, 1912 - December 24, 1926
if (y > 1912 || (y == 1912 && (m > 7 || (m == 7 && day >= 30)))) return "taisho";
- // Meiji: January 25, 1873 - July 29, 1912
- if (y > 1873 || (y == 1873 && (m > 1 || (m == 1 && day >= 25)))) return "meiji";
+ // Meiji: year 1873+ (Japan adopted Gregorian calendar in Meiji 6)
+ if (y >= 1873) return "meiji";
// Before Meiji
return y >= 1 ? "ce" : "bce";
}
@@ -2132,7 +2208,7 @@ private static int JapaneseEraYear(in IsoDate d)
"heisei" => d.Year - 1988,
"showa" => d.Year - 1925,
"taisho" => d.Year - 1911,
- "meiji" => d.Year - 1872,
+ "meiji" => d.Year - 1867,
"bce" => 1 - d.Year,
_ => d.Year // "ce"
};
@@ -2198,9 +2274,9 @@ private static int ComputeYearFromEra(Realm realm, string calendar, string era,
if (era is "heisei") return eraYear + 1988;
if (era is "showa") return eraYear + 1925;
if (era is "taisho") return eraYear + 1911;
- if (era is "meiji") return eraYear + 1872;
- if (era is "ce" or "gregory") return eraYear;
- if (era is "bce" or "gregory-inverse") return 1 - eraYear;
+ if (era is "meiji") return eraYear + 1867;
+ if (era is "ce" or "ad" or "gregory") return eraYear;
+ if (era is "bce" or "bc" or "gregory-inverse") return 1 - eraYear;
break;
case "roc":
if (era is "roc" or "minguo")
diff --git a/Jint/Native/Temporal/ZonedDateTime/ZonedDateTimeConstructor.cs b/Jint/Native/Temporal/ZonedDateTime/ZonedDateTimeConstructor.cs
index 7c43987962..e2f29c2c0a 100644
--- a/Jint/Native/Temporal/ZonedDateTime/ZonedDateTimeConstructor.cs
+++ b/Jint/Native/Temporal/ZonedDateTime/ZonedDateTimeConstructor.cs
@@ -194,6 +194,8 @@ private JsZonedDateTime ToZonedDateTimeFromFieldsWithOptions(ObjectInstance obj,
calendar = TemporalHelpers.ToTemporalCalendarIdentifier(_realm, calendarProp);
}
+ TemporalHelpers.RejectTemporalUnsupportedCalendar(_realm, calendar);
+
// 2. day - read and convert immediately
var dayValue = obj.Get("day");
if (dayValue.IsUndefined())
diff --git a/Jint/Native/Temporal/ZonedDateTime/ZonedDateTimePrototype.cs b/Jint/Native/Temporal/ZonedDateTime/ZonedDateTimePrototype.cs
index 9ec7725c8e..05930ac01c 100644
--- a/Jint/Native/Temporal/ZonedDateTime/ZonedDateTimePrototype.cs
+++ b/Jint/Native/Temporal/ZonedDateTime/ZonedDateTimePrototype.cs
@@ -194,8 +194,12 @@ private JsBigInt GetEpochNanoseconds(JsValue thisObject, JsCallArguments argumen
private JsNumber GetDayOfWeek(JsValue thisObject, JsCallArguments arguments) =>
JsNumber.Create(ValidateZonedDateTime(thisObject).GetIsoDateTime().Date.DayOfWeek());
- private JsNumber GetDayOfYear(JsValue thisObject, JsCallArguments arguments) =>
- JsNumber.Create(ValidateZonedDateTime(thisObject).GetIsoDateTime().Date.DayOfYear());
+ private JsNumber GetDayOfYear(JsValue thisObject, JsCallArguments arguments)
+ {
+ var zdt = ValidateZonedDateTime(thisObject);
+ var date = zdt.GetIsoDateTime().Date;
+ return JsNumber.Create(TemporalHelpers.CalendarDayOfYear(zdt.Calendar, date));
+ }
private JsValue GetWeekOfYear(JsValue thisObject, JsCallArguments arguments)
{
@@ -327,7 +331,7 @@ private JsZonedDateTime With(JsValue thisObject, JsCallArguments arguments)
// Each field is read and immediately converted, defaulting to current value if undefined
// Track if at least one property is present
- var isNonIso = NonIsoCalendars.IsNonIsoCalendar(zdt.Calendar);
+ var isNonIso8601 = zdt.Calendar is not "iso8601" and not "gregory";
var dayValue = obj.Get("day");
int day;
@@ -337,7 +341,7 @@ private JsZonedDateTime With(JsValue thisObject, JsCallArguments arguments)
}
else
{
- day = isNonIso
+ day = isNonIso8601
? TemporalHelpers.CalendarDay(zdt.Calendar, current.Date)
: current.Day;
}
@@ -364,7 +368,7 @@ private JsZonedDateTime With(JsValue thisObject, JsCallArguments arguments)
}
else
{
- month = isNonIso
+ month = isNonIso8601
? TemporalHelpers.CalendarMonth(zdt.Calendar, current.Date)
: current.Month;
}
@@ -401,7 +405,7 @@ private JsZonedDateTime With(JsValue thisObject, JsCallArguments arguments)
monthCode = TypeConverter.ToString(monthCodeValue);
}
}
- else if (isNonIso && !monthExplicit)
+ else if (isNonIso8601 && !monthExplicit)
{
monthCode = TemporalHelpers.CalendarMonthCode(zdt.Calendar, current.Date);
}
@@ -428,16 +432,40 @@ private JsZonedDateTime With(JsValue thisObject, JsCallArguments arguments)
}
else
{
- year = isNonIso
+ year = isNonIso8601
? TemporalHelpers.CalendarYear(zdt.Calendar, current.Date)
: current.Year;
}
+ // Read era/eraYear only for calendars that support them
+ var hasEraFields = false;
+ if (TemporalHelpers.CalendarUsesEras(zdt.Calendar))
+ {
+ var eraValue = obj.Get("era");
+ var eraYearValue = obj.Get("eraYear");
+ if (!eraValue.IsUndefined() || !eraYearValue.IsUndefined())
+ {
+ hasEraFields = true;
+ if (!eraValue.IsUndefined() && !eraYearValue.IsUndefined())
+ {
+ var eraYear2 = TemporalHelpers.ReadEraFields(_realm, obj, zdt.Calendar);
+ if (eraYear2.HasValue)
+ {
+ year = eraYear2.Value;
+ }
+ }
+ else
+ {
+ Throw.TypeError(_realm, "Both era and eraYear must be provided together");
+ }
+ }
+ }
+
// Check that at least one property is present
if (dayValue.IsUndefined() && hourValue.IsUndefined() && microsecondValue.IsUndefined() &&
millisecondValue.IsUndefined() && minuteValue.IsUndefined() && monthValue.IsUndefined() &&
monthCodeValue.IsUndefined() && nanosecondValue.IsUndefined() && offsetValue.IsUndefined() &&
- secondValue.IsUndefined() && yearValue.IsUndefined())
+ secondValue.IsUndefined() && yearValue.IsUndefined() && !hasEraFields)
{
Throw.TypeError(_realm, "with() requires at least one temporal property");
}
@@ -477,46 +505,33 @@ private JsZonedDateTime With(JsValue thisObject, JsCallArguments arguments)
// Parse and validate monthCode
int? parsedMonthCode = null;
- if (monthCode is not null)
+ if (!isNonIso8601 || TemporalHelpers.IsGregorianBasedCalendar(zdt.Calendar))
{
- // Parse monthCode for well-formedness
- parsedMonthCode = TemporalHelpers.ParseMonthCode(_realm, monthCode);
-
- if (!isNonIso)
- {
- // For ISO 8601 calendar: validate monthCode is valid (01-12, no leap months)
- if (monthCode.Length == 4 && monthCode[3] == 'L')
- {
- Throw.RangeError(_realm, $"Leap months are not valid for ISO 8601 calendar: {monthCode}");
- }
-
- if (parsedMonthCode.Value < 1 || parsedMonthCode.Value > 12)
- {
- Throw.RangeError(_realm, $"Month {parsedMonthCode.Value} is not valid for ISO 8601 calendar");
- }
- }
+ // ISO/Gregorian-based: validate no leap months, month/monthCode consistency
+ parsedMonthCode = TemporalHelpers.ValidateMonthCodeForNonLeapCalendar(
+ _realm, monthCode, !monthValue.IsUndefined() ? month : null);
- // Check if month property was explicitly provided (not just defaulted)
- // Use the monthValue that was already read earlier
- if (!monthValue.IsUndefined())
+ if (parsedMonthCode.HasValue)
{
- // Both month and monthCode provided - they must match
- if (month != parsedMonthCode.Value)
- {
- Throw.RangeError(_realm, "month and monthCode must match");
- }
+ month = parsedMonthCode.Value;
}
+ }
+ else if (monthCode is not null)
+ {
+ // Non-ISO: just parse for well-formedness, let CalendarDateToISO handle validation
+ parsedMonthCode = TemporalHelpers.ParseMonthCode(_realm, monthCode);
- // Use monthCode if provided (for ISO calendars)
- if (!isNonIso)
+ // When monthCode is explicitly provided but month is not, signal CalendarDateToIso
+ // to use monthCode by passing month=0 (avoids month/monthCode mismatch rejection)
+ if (monthValue.IsUndefined())
{
- month = parsedMonthCode.Value;
+ month = 0;
}
}
// Regulate date with user's overflow option
IsoDate? date;
- if (isNonIso)
+ if (isNonIso8601)
{
date = TemporalHelpers.CalendarDateToISO(_realm, zdt.Calendar, year, month, day, overflow, monthCode);
}