From 0fa672f26e32d80a7af54c37967b9c8c7bfa8a63 Mon Sep 17 00:00:00 2001 From: Philip Chimento Date: Mon, 24 Nov 2025 12:57:40 -0800 Subject: [PATCH] Intl Era Monthcode: Test constraining day in islamic-umalqura calendar Similar to https://github.com/tc39/test262/pull/4700 but this is for an observational Hijri calendar, not a tabular one. Any month may have either 29 or 30 days in any year. So we additionally test adding or subtracting 1 year from day 30 of a month, and landing in a year where that month has 29 days. Observational month lengths are provided in a comment for convenience. --- .../add/constrain-day-islamic-umalqura.js | 284 +++++++++++++++++- .../constrain-day-islamic-umalqura.js | 284 +++++++++++++++++- .../with/constrain-day-islamic-umalqura.js | 174 +++++++++++ .../add/constrain-day-islamic-umalqura.js | 284 +++++++++++++++++- .../constrain-day-islamic-umalqura.js | 284 +++++++++++++++++- .../with/constrain-day-islamic-umalqura.js | 174 +++++++++++ .../add/constrain-day-islamic-umalqura.js | 284 +++++++++++++++++- .../constrain-day-islamic-umalqura.js | 284 +++++++++++++++++- .../with/constrain-day-islamic-umalqura.js | 174 +++++++++++ 9 files changed, 2130 insertions(+), 96 deletions(-) create mode 100644 test/intl402/Temporal/PlainDate/prototype/with/constrain-day-islamic-umalqura.js create mode 100644 test/intl402/Temporal/PlainDateTime/prototype/with/constrain-day-islamic-umalqura.js create mode 100644 test/intl402/Temporal/ZonedDateTime/prototype/with/constrain-day-islamic-umalqura.js diff --git a/test/intl402/Temporal/PlainDate/prototype/add/constrain-day-islamic-umalqura.js b/test/intl402/Temporal/PlainDate/prototype/add/constrain-day-islamic-umalqura.js index 3a10b55d83..8c8e4f8c8d 100644 --- a/test/intl402/Temporal/PlainDate/prototype/add/constrain-day-islamic-umalqura.js +++ b/test/intl402/Temporal/PlainDate/prototype/add/constrain-day-islamic-umalqura.js @@ -11,30 +11,282 @@ features: [Temporal, Intl.Era-monthcode] const calendar = "islamic-umalqura"; const options = { overflow: "reject" }; +// Observational month lengths in AH year: +// Y \ M 1 2 3 4 5 6 7 8 9 10 11 12 +// 1442: 29 30 29 30 29 30 29 30 30 29 30 29 +// 1443: 30 29 30 29 30 29 30 29 30 29 30 30 +// 1444: 29 30 29 30 30 29 29 30 29 30 29 30 + // Years +const years1 = new Temporal.Duration(/* years = */ 1); +const years1n = new Temporal.Duration(-1); + +for (const monthCode of ["M01", "M03", "M05", "M07", "M12"]) { + const date1443 = Temporal.PlainDate.from({ year: 1443, monthCode, day: 30, calendar }, options); + TemporalHelpers.assertPlainDate( + date1443.add(years1n), + 1442, Number(monthCode.slice(1)), monthCode, 29, `Subtracting 1 year from ${monthCode}-30 into 29-day ${monthCode} constrains`, + "ah", 1442 + ); + + assert.throws(RangeError, function () { + date1443.add(years1n, options); + }, `Subtracting 1 year from ${monthCode}-30 into 29-day ${monthCode} rejects`); +} + +for (const monthCode of ["M02", "M04", "M06", "M08"]) { + const date1442 = Temporal.PlainDate.from({ year: 1442, monthCode, day: 30, calendar }, options); + TemporalHelpers.assertPlainDate( + date1442.add(years1), + 1443, Number(monthCode.slice(1)), monthCode, 29, `Adding 1 year to ${monthCode}-30 into 29-day ${monthCode} constrains`, + "ah", 1443 + ); + + assert.throws(RangeError, function () { + date1442.add(years1, options); + }, `Adding 1 year to ${monthCode}-30 into 29-day ${monthCode} rejects`); +} + +for (const monthCode of ["M09", "M11"]) { + const date1443 = Temporal.PlainDate.from({ year: 1443, monthCode, day: 30, calendar }, options); + TemporalHelpers.assertPlainDate( + date1443.add(years1), + 1444, Number(monthCode.slice(1)), monthCode, 29, `Adding 1 year to ${monthCode}-30 into 29-day ${monthCode} constrains`, + "ah", 1444 + ); + + assert.throws(RangeError, function () { + date1443.add(years1, options); + }, `Adding 1 year to ${monthCode}-30 into 29-day ${monthCode} rejects`); +} + +const date1444 = Temporal.PlainDate.from({ year: 1444, monthCode: "M10", day: 30, calendar }, options); +TemporalHelpers.assertPlainDate( + date1444.add(years1n), + 1443, 10, "M10", 29, `Subtracting 1 year from Shawwal 30 into 29-day Shawwal constrains`, + "ah", 1443 +); + +assert.throws(RangeError, function () { + date1444.add(years1n, options); +}, `Subtracting 1 year from Shawwal 30 into 29-day Shawwal rejects`); + // Months const months1 = new Temporal.Duration(0, /* months = */ 1); +const months3 = new Temporal.Duration(0, 3); +const months5 = new Temporal.Duration(0, 5); +const months7 = new Temporal.Duration(0, 7); +const months8 = new Temporal.Duration(0, 8); +const months9 = new Temporal.Duration(0, 9); +const months10 = new Temporal.Duration(0, 10); const months1n = new Temporal.Duration(0, -1); +const months3n = new Temporal.Duration(0, -3); +const months4n = new Temporal.Duration(0, -4); +const months6n = new Temporal.Duration(0, -6); +const months8n = new Temporal.Duration(0, -8); +const months10n = new Temporal.Duration(0, -10); -const date1 = Temporal.PlainDate.from({ year: 1447, monthCode: "M01", day: 30, calendar }, options); -TemporalHelpers.assertPlainDate( - date1.add(months1), - 1447, 2, "M02", 29, "Day is constrained when adding months to a 30-day month and landing in a 29-day month", - "ah", 1447 -); +const date14420230 = Temporal.PlainDate.from({ year: 1442, monthCode: "M02", day: 30, calendar }, options); +const date14430130 = Temporal.PlainDate.from({ year: 1443, monthCode: "M01", day: 30, calendar }, options); +const date14440230 = Temporal.PlainDate.from({ year: 1444, monthCode: "M02", day: 30, calendar} , options); +const date14421130 = Temporal.PlainDate.from({ year: 1442, monthCode: "M11", day: 30, calendar }, options); +const date14431230 = Temporal.PlainDate.from({ year: 1443, monthCode: "M12", day: 30, calendar }, options); +const date14441230 = Temporal.PlainDate.from({ year: 1444, monthCode: "M12", day: 30, calendar} , options); -assert.throws(RangeError, function () { - date1.add(months1, options); -}, "Adding months to a 30-day month and landing in a 29-day month rejects"); +// Forwards TemporalHelpers.assertPlainDate( - date1.add(months1n), - 1446, 12, "M12", 29, "Day is constrained when subtracting months from a 30-day month and landing in a 29-day month", - "ah", 1446 -); - + date14431230.add(months1), + 1444, 1, "M01", 29, "29-day Muharram constrains", + "ah", 1444); assert.throws(RangeError, function () { - date1.add(months1n, options); -}, "Subtracting months from a 30-day month and landing in a 29-day month rejects"); + date14431230.add(months4n, options); +}, "29-day Muharram rejects with 30"); + +TemporalHelpers.assertPlainDate( + date14430130.add(months1), + 1443, 2, "M02", 29, "29-day Safar constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14430130.add(months1, options); +}, "29-day Safar rejects with 30"); + +TemporalHelpers.assertPlainDate( + date14420230.add(months1), + 1442, 3, "M03", 29, "29-day Rabi' al-Awwal constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14420230.add(months1, options); +}, "29-day Rabi' al-Awwal rejects with 30"); + +TemporalHelpers.assertPlainDate( + date14430130.add(months3), + 1443, 4, "M04", 29, "29-day Rabi' al-Thani constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14430130.add(months3, options); +}, "29-day Rabi' al-Thani rejects with 30"); + +TemporalHelpers.assertPlainDate( + date14420230.add(months3), + 1442, 5, "M05", 29, "29-day Jumada al-Awwal constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14420230.add(months3, options); +}, "29-day Jumada al-Awwal rejects with 30"); + +TemporalHelpers.assertPlainDate( + date14430130.add(months5), + 1443, 6, "M06", 29, "29-day Jumada al-Thani constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14430130.add(months5, options); +}, "29-day Jumada al-Thani rejects with 30"); + +TemporalHelpers.assertPlainDate( + date14420230.add(months5), + 1442, 7, "M07", 29, "29-day Rajab constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14420230.add(months5, options); +}, "29-day Rajab rejects with 30"); + +TemporalHelpers.assertPlainDate( + date14430130.add(months7), + 1443, 8, "M08", 29, "29-day Sha'ban constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14430130.add(months7, options); +}, "29-day Sha'ban rejects with 30"); + +TemporalHelpers.assertPlainDate( + date14440230.add(months7), + 1444, 9, "M09", 29, "29-day Ramadan constrains", + "ah", 1444); +assert.throws(RangeError, function () { + date14440230.add(months7, options); +}, "29-day Ramadan rejects with 30"); + +TemporalHelpers.assertPlainDate( + date14420230.add(months8), + 1442, 10, "M10", 29, "29-day Shawwal constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14420230.add(months8, options); +}, "29-day Shawwal rejects with 30"); + +TemporalHelpers.assertPlainDate( + date14440230.add(months9), + 1444, 11, "M11", 29, "29-day Dhu al-Qadah constrains", + "ah", 1444); +assert.throws(RangeError, function () { + date14440230.add(months9, options); +}, "29-day Dhu al-Qadah rejects with 30"); + +TemporalHelpers.assertPlainDate( + date14420230.add(months10), + 1442, 12, "M12", 29, "29-day Dhu al-Hijjah constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14420230.add(months10, options); +}, "29-day Dhu al-Hijjah rejects with 30"); + +// Backwards + +TemporalHelpers.assertPlainDate( + date14421130.add(months10n), + 1442, 1, "M01", 29, "29-day Muharram constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14421130.add(months10n, options); +}, "29-day Muharram rejects with 30"); + +TemporalHelpers.assertPlainDate( + date14431230.add(months10n), + 1443, 2, "M02", 29, "29-day Safar constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14431230.add(months10n, options); +}, "29-day Safar rejects with 30"); + +TemporalHelpers.assertPlainDate( + date14421130.add(months8n), + 1442, 3, "M03", 29, "29-day Rabi' al-Awwal constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14421130.add(months8n, options); +}, "29-day Rabi' al-Awwal rejects with 30"); + +TemporalHelpers.assertPlainDate( + date14431230.add(months8n), + 1443, 4, "M04", 29, "29-day Rabi' al-Thani constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14431230.add(months8n, options); +}, "29-day Rabi' al-Thani rejects with 30"); + +TemporalHelpers.assertPlainDate( + date14421130.add(months6n), + 1442, 5, "M05", 29, "29-day Jumada al-Awwal constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14421130.add(months6n, options); +}, "29-day Jumada al-Awwal rejects with 30"); + +TemporalHelpers.assertPlainDate( + date14431230.add(months6n), + 1443, 6, "M06", 29, "29-day Jumada al-Thani constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14431230.add(months6n, options); +}, "29-day Jumada al-Thani rejects with 30"); + +TemporalHelpers.assertPlainDate( + date14421130.add(months4n), + 1442, 7, "M07", 29, "29-day Rajab constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14421130.add(months4n, options); +}, "29-day Rajab rejects with 30"); + +TemporalHelpers.assertPlainDate( + date14431230.add(months4n), + 1443, 8, "M08", 29, "29-day Sha'ban constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14431230.add(months4n, options); +}, "29-day Sha'ban rejects with 30"); + +TemporalHelpers.assertPlainDate( + date14441230.add(months3n), + 1444, 9, "M09", 29, "29-day Ramadan constrains", + "ah", 1444); +assert.throws(RangeError, function () { + date14441230.add(months3n, options); +}, "29-day Ramadan rejects with 30"); + +TemporalHelpers.assertPlainDate( + date14421130.add(months1n), + 1442, 10, "M10", 29, "29-day Shawwal constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14421130.add(months1n, options); +}, "29-day Shawwal rejects with 30"); + +TemporalHelpers.assertPlainDate( + date14441230.add(months1n), + 1444, 11, "M11", 29, "29-day Dhu al-Qadah constrains", + "ah", 1444); +assert.throws(RangeError, function () { + date14441230.add(months1n, options); +}, "29-day Dhu al-Qadah rejects with 30"); + +TemporalHelpers.assertPlainDate( + date14430130.add(months1n), + 1442, 12, "M12", 29, "29-day Dhu al-Hijjah constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14430130.add(months1n, options); +}, "29-day Dhu al-Hijjah rejects with 30"); diff --git a/test/intl402/Temporal/PlainDate/prototype/subtract/constrain-day-islamic-umalqura.js b/test/intl402/Temporal/PlainDate/prototype/subtract/constrain-day-islamic-umalqura.js index 624660e38f..67be6d16f4 100644 --- a/test/intl402/Temporal/PlainDate/prototype/subtract/constrain-day-islamic-umalqura.js +++ b/test/intl402/Temporal/PlainDate/prototype/subtract/constrain-day-islamic-umalqura.js @@ -11,30 +11,282 @@ features: [Temporal, Intl.Era-monthcode] const calendar = "islamic-umalqura"; const options = { overflow: "reject" }; +// Observational month lengths in AH year: +// Y \ M 1 2 3 4 5 6 7 8 9 10 11 12 +// 1442: 29 30 29 30 29 30 29 30 30 29 30 29 +// 1443: 30 29 30 29 30 29 30 29 30 29 30 30 +// 1444: 29 30 29 30 30 29 29 30 29 30 29 30 + // Years +const years1 = new Temporal.Duration(/* years = */ -1); +const years1n = new Temporal.Duration(1); + +for (const monthCode of ["M01", "M03", "M05", "M07", "M12"]) { + const date1443 = Temporal.PlainDate.from({ year: 1443, monthCode, day: 30, calendar }, options); + TemporalHelpers.assertPlainDate( + date1443.subtract(years1n), + 1442, Number(monthCode.slice(1)), monthCode, 29, `Subtracting 1 year from ${monthCode}-30 into 29-day ${monthCode} constrains`, + "ah", 1442 + ); + + assert.throws(RangeError, function () { + date1443.subtract(years1n, options); + }, `Subtracting 1 year from ${monthCode}-30 into 29-day ${monthCode} rejects`); +} + +for (const monthCode of ["M02", "M04", "M06", "M08"]) { + const date1442 = Temporal.PlainDate.from({ year: 1442, monthCode, day: 30, calendar }, options); + TemporalHelpers.assertPlainDate( + date1442.subtract(years1), + 1443, Number(monthCode.slice(1)), monthCode, 29, `Adding 1 year to ${monthCode}-30 into 29-day ${monthCode} constrains`, + "ah", 1443 + ); + + assert.throws(RangeError, function () { + date1442.subtract(years1, options); + }, `Adding 1 year to ${monthCode}-30 into 29-day ${monthCode} rejects`); +} + +for (const monthCode of ["M09", "M11"]) { + const date1443 = Temporal.PlainDate.from({ year: 1443, monthCode, day: 30, calendar }, options); + TemporalHelpers.assertPlainDate( + date1443.subtract(years1), + 1444, Number(monthCode.slice(1)), monthCode, 29, `Adding 1 year to ${monthCode}-30 into 29-day ${monthCode} constrains`, + "ah", 1444 + ); + + assert.throws(RangeError, function () { + date1443.subtract(years1, options); + }, `Adding 1 year to ${monthCode}-30 into 29-day ${monthCode} rejects`); +} + +const date1444 = Temporal.PlainDate.from({ year: 1444, monthCode: "M10", day: 30, calendar }, options); +TemporalHelpers.assertPlainDate( + date1444.subtract(years1n), + 1443, 10, "M10", 29, `Subtracting 1 year from Shawwal 30 into 29-day Shawwal constrains`, + "ah", 1443 +); + +assert.throws(RangeError, function () { + date1444.subtract(years1n, options); +}, `Subtracting 1 year from Shawwal 30 into 29-day Shawwal rejects`); + // Months const months1 = new Temporal.Duration(0, /* months = */ -1); +const months3 = new Temporal.Duration(0, -3); +const months5 = new Temporal.Duration(0, -5); +const months7 = new Temporal.Duration(0, -7); +const months8 = new Temporal.Duration(0, -8); +const months9 = new Temporal.Duration(0, -9); +const months10 = new Temporal.Duration(0, -10); const months1n = new Temporal.Duration(0, 1); +const months3n = new Temporal.Duration(0, 3); +const months4n = new Temporal.Duration(0, 4); +const months6n = new Temporal.Duration(0, 6); +const months8n = new Temporal.Duration(0, 8); +const months10n = new Temporal.Duration(0, 10); -const date1 = Temporal.PlainDate.from({ year: 1447, monthCode: "M01", day: 30, calendar }, options); -TemporalHelpers.assertPlainDate( - date1.subtract(months1), - 1447, 2, "M02", 29, "Day is constrained when adding months to a 30-day month and landing in a 29-day month", - "ah", 1447 -); +const date14420230 = Temporal.PlainDate.from({ year: 1442, monthCode: "M02", day: 30, calendar }, options); +const date14430130 = Temporal.PlainDate.from({ year: 1443, monthCode: "M01", day: 30, calendar }, options); +const date14440230 = Temporal.PlainDate.from({ year: 1444, monthCode: "M02", day: 30, calendar} , options); +const date14421130 = Temporal.PlainDate.from({ year: 1442, monthCode: "M11", day: 30, calendar }, options); +const date14431230 = Temporal.PlainDate.from({ year: 1443, monthCode: "M12", day: 30, calendar }, options); +const date14441230 = Temporal.PlainDate.from({ year: 1444, monthCode: "M12", day: 30, calendar} , options); -assert.throws(RangeError, function () { - date1.subtract(months1, options); -}, "Adding months to a 30-day month and landing in a 29-day month rejects"); +// Forwards TemporalHelpers.assertPlainDate( - date1.subtract(months1n), - 1446, 12, "M12", 29, "Day is constrained when subtracting months from a 30-day month and landing in a 29-day month", - "ah", 1446 -); - + date14431230.subtract(months1), + 1444, 1, "M01", 29, "29-day Muharram constrains", + "ah", 1444); assert.throws(RangeError, function () { - date1.subtract(months1n, options); -}, "Subtracting months from a 30-day month and landing in a 29-day month rejects"); + date14431230.subtract(months4n, options); +}, "29-day Muharram rejects with 30"); + +TemporalHelpers.assertPlainDate( + date14430130.subtract(months1), + 1443, 2, "M02", 29, "29-day Safar constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14430130.subtract(months1, options); +}, "29-day Safar rejects with 30"); + +TemporalHelpers.assertPlainDate( + date14420230.subtract(months1), + 1442, 3, "M03", 29, "29-day Rabi' al-Awwal constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14420230.subtract(months1, options); +}, "29-day Rabi' al-Awwal rejects with 30"); + +TemporalHelpers.assertPlainDate( + date14430130.subtract(months3), + 1443, 4, "M04", 29, "29-day Rabi' al-Thani constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14430130.subtract(months3, options); +}, "29-day Rabi' al-Thani rejects with 30"); + +TemporalHelpers.assertPlainDate( + date14420230.subtract(months3), + 1442, 5, "M05", 29, "29-day Jumada al-Awwal constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14420230.subtract(months3, options); +}, "29-day Jumada al-Awwal rejects with 30"); + +TemporalHelpers.assertPlainDate( + date14430130.subtract(months5), + 1443, 6, "M06", 29, "29-day Jumada al-Thani constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14430130.subtract(months5, options); +}, "29-day Jumada al-Thani rejects with 30"); + +TemporalHelpers.assertPlainDate( + date14420230.subtract(months5), + 1442, 7, "M07", 29, "29-day Rajab constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14420230.subtract(months5, options); +}, "29-day Rajab rejects with 30"); + +TemporalHelpers.assertPlainDate( + date14430130.subtract(months7), + 1443, 8, "M08", 29, "29-day Sha'ban constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14430130.subtract(months7, options); +}, "29-day Sha'ban rejects with 30"); + +TemporalHelpers.assertPlainDate( + date14440230.subtract(months7), + 1444, 9, "M09", 29, "29-day Ramadan constrains", + "ah", 1444); +assert.throws(RangeError, function () { + date14440230.subtract(months7, options); +}, "29-day Ramadan rejects with 30"); + +TemporalHelpers.assertPlainDate( + date14420230.subtract(months8), + 1442, 10, "M10", 29, "29-day Shawwal constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14420230.subtract(months8, options); +}, "29-day Shawwal rejects with 30"); + +TemporalHelpers.assertPlainDate( + date14440230.subtract(months9), + 1444, 11, "M11", 29, "29-day Dhu al-Qadah constrains", + "ah", 1444); +assert.throws(RangeError, function () { + date14440230.subtract(months9, options); +}, "29-day Dhu al-Qadah rejects with 30"); + +TemporalHelpers.assertPlainDate( + date14420230.subtract(months10), + 1442, 12, "M12", 29, "29-day Dhu al-Hijjah constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14420230.subtract(months10, options); +}, "29-day Dhu al-Hijjah rejects with 30"); + +// Backwards + +TemporalHelpers.assertPlainDate( + date14421130.subtract(months10n), + 1442, 1, "M01", 29, "29-day Muharram constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14421130.subtract(months10n, options); +}, "29-day Muharram rejects with 30"); + +TemporalHelpers.assertPlainDate( + date14431230.subtract(months10n), + 1443, 2, "M02", 29, "29-day Safar constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14431230.subtract(months10n, options); +}, "29-day Safar rejects with 30"); + +TemporalHelpers.assertPlainDate( + date14421130.subtract(months8n), + 1442, 3, "M03", 29, "29-day Rabi' al-Awwal constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14421130.subtract(months8n, options); +}, "29-day Rabi' al-Awwal rejects with 30"); + +TemporalHelpers.assertPlainDate( + date14431230.subtract(months8n), + 1443, 4, "M04", 29, "29-day Rabi' al-Thani constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14431230.subtract(months8n, options); +}, "29-day Rabi' al-Thani rejects with 30"); + +TemporalHelpers.assertPlainDate( + date14421130.subtract(months6n), + 1442, 5, "M05", 29, "29-day Jumada al-Awwal constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14421130.subtract(months6n, options); +}, "29-day Jumada al-Awwal rejects with 30"); + +TemporalHelpers.assertPlainDate( + date14431230.subtract(months6n), + 1443, 6, "M06", 29, "29-day Jumada al-Thani constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14431230.subtract(months6n, options); +}, "29-day Jumada al-Thani rejects with 30"); + +TemporalHelpers.assertPlainDate( + date14421130.subtract(months4n), + 1442, 7, "M07", 29, "29-day Rajab constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14421130.subtract(months4n, options); +}, "29-day Rajab rejects with 30"); + +TemporalHelpers.assertPlainDate( + date14431230.subtract(months4n), + 1443, 8, "M08", 29, "29-day Sha'ban constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14431230.subtract(months4n, options); +}, "29-day Sha'ban rejects with 30"); + +TemporalHelpers.assertPlainDate( + date14441230.subtract(months3n), + 1444, 9, "M09", 29, "29-day Ramadan constrains", + "ah", 1444); +assert.throws(RangeError, function () { + date14441230.subtract(months3n, options); +}, "29-day Ramadan rejects with 30"); + +TemporalHelpers.assertPlainDate( + date14421130.subtract(months1n), + 1442, 10, "M10", 29, "29-day Shawwal constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14421130.subtract(months1n, options); +}, "29-day Shawwal rejects with 30"); + +TemporalHelpers.assertPlainDate( + date14441230.subtract(months1n), + 1444, 11, "M11", 29, "29-day Dhu al-Qadah constrains", + "ah", 1444); +assert.throws(RangeError, function () { + date14441230.subtract(months1n, options); +}, "29-day Dhu al-Qadah rejects with 30"); + +TemporalHelpers.assertPlainDate( + date14430130.subtract(months1n), + 1442, 12, "M12", 29, "29-day Dhu al-Hijjah constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14430130.subtract(months1n, options); +}, "29-day Dhu al-Hijjah rejects with 30"); diff --git a/test/intl402/Temporal/PlainDate/prototype/with/constrain-day-islamic-umalqura.js b/test/intl402/Temporal/PlainDate/prototype/with/constrain-day-islamic-umalqura.js new file mode 100644 index 0000000000..84246a8ad0 --- /dev/null +++ b/test/intl402/Temporal/PlainDate/prototype/with/constrain-day-islamic-umalqura.js @@ -0,0 +1,174 @@ +// Copyright (C) 2025 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindate.prototype.with +description: Constraining the day for 29/30-day months in islamic-umalqura calendar +includes: [temporalHelpers.js] +features: [Temporal, Intl.Era-monthcode] +---*/ + +const calendar = "islamic-umalqura"; +const options = { overflow: "reject" }; + +// Observational month lengths in AH year: +// Y \ M 1 2 3 4 5 6 7 8 9 10 11 12 +// 1442: 29 30 29 30 29 30 29 30 30 29 30 29 +// 1443: 30 29 30 29 30 29 30 29 30 29 30 30 +// 1444: 29 30 29 30 30 29 29 30 29 30 29 30 + +// Years + +for (const monthCode of ["M01", "M03", "M05", "M07", "M12"]) { + const date1443 = Temporal.PlainDate.from({ year: 1443, monthCode, day: 30, calendar }, options); + TemporalHelpers.assertPlainDate( + date1443.with({ year: 1442 }), + 1442, Number(monthCode.slice(1)), monthCode, 29, `Changing the year from ${monthCode}-30 into 29-day ${monthCode} constrains`, + "ah", 1442 + ); + + assert.throws(RangeError, function () { + date1443.with({ year: 1442 }, options); + }, `Changing the year from ${monthCode}-30 into 29-day ${monthCode} rejects`); +} + +for (const monthCode of ["M02", "M04", "M06", "M08"]) { + const date1442 = Temporal.PlainDate.from({ year: 1442, monthCode, day: 30, calendar }, options); + TemporalHelpers.assertPlainDate( + date1442.with({ year: 1443 }), + 1443, Number(monthCode.slice(1)), monthCode, 29, `Changing the year from ${monthCode}-30 into 29-day ${monthCode} constrains`, + "ah", 1443 + ); + + assert.throws(RangeError, function () { + date1442.with({ year: 1443 }, options); + }, `Changing the year from ${monthCode}-30 into 29-day ${monthCode} rejects`); +} + +for (const monthCode of ["M09", "M11"]) { + const date1443 = Temporal.PlainDate.from({ year: 1443, monthCode, day: 30, calendar }, options); + TemporalHelpers.assertPlainDate( + date1443.with({ year: 1444 }), + 1444, Number(monthCode.slice(1)), monthCode, 29, `Changing the year from ${monthCode}-30 into 29-day ${monthCode} constrains`, + "ah", 1444 + ); + + assert.throws(RangeError, function () { + date1443.with({ year: 1444 }, options); + }, `Changing the year from ${monthCode}-30 into 29-day ${monthCode} rejects`); +} + +const date1444 = Temporal.PlainDate.from({ year: 1444, monthCode: "M10", day: 30, calendar }, options); +TemporalHelpers.assertPlainDate( + date1444.with({ year: 1443 }), + 1443, 10, "M10", 29, `Changing the year from Shawwal 30 into 29-day Shawwal constrains`, + "ah", 1443 +); + +assert.throws(RangeError, function () { + date1444.with({ year: 1443 }, options); +}, `Changing the year from Shawwal 30 into 29-day Shawwal rejects`); + +// Months + +const date14420230 = Temporal.PlainDate.from({ year: 1442, monthCode: "M02", day: 30, calendar }, options); +const date14430130 = Temporal.PlainDate.from({ year: 1443, monthCode: "M01", day: 30, calendar }, options); +const date14441230 = Temporal.PlainDate.from({ year: 1444, monthCode: "M12", day: 30, calendar} , options); + +// Forwards + +TemporalHelpers.assertPlainDate( + date14441230.with({ monthCode: "M01" }), + 1444, 1, "M01", 29, "29-day Muharram constrains", + "ah", 1444); +assert.throws(RangeError, function () { + date14441230.with({ monthCode: "M01" }, options); +}, "29-day Muharram rejects with 30"); + +TemporalHelpers.assertPlainDate( + date14430130.with({ monthCode: "M02" }), + 1443, 2, "M02", 29, "29-day Safar constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14430130.with({ monthCode: "M02" }, options); +}, "29-day Safar rejects with 30"); + +TemporalHelpers.assertPlainDate( + date14420230.with({ monthCode: "M03" }), + 1442, 3, "M03", 29, "29-day Rabi' al-Awwal constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14420230.with({ monthCode: "M03" }, options); +}, "29-day Rabi' al-Awwal rejects with 30"); + +TemporalHelpers.assertPlainDate( + date14430130.with({ monthCode: "M04" }), + 1443, 4, "M04", 29, "29-day Rabi' al-Thani constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14430130.with({ monthCode: "M04" }, options); +}, "29-day Rabi' al-Thani rejects with 30"); + +TemporalHelpers.assertPlainDate( + date14420230.with({ monthCode: "M05" }), + 1442, 5, "M05", 29, "29-day Jumada al-Awwal constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14420230.with({ monthCode: "M05" }, options); +}, "29-day Jumada al-Awwal rejects with 30"); + +TemporalHelpers.assertPlainDate( + date14430130.with({ monthCode: "M06" }), + 1443, 6, "M06", 29, "29-day Jumada al-Thani constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14430130.with({ monthCode: "M06" }, options); +}, "29-day Jumada al-Thani rejects with 30"); + +TemporalHelpers.assertPlainDate( + date14420230.with({ monthCode: "M07" }), + 1442, 7, "M07", 29, "29-day Rajab constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14420230.with({ monthCode: "M07" }, options); +}, "29-day Rajab rejects with 30"); + +TemporalHelpers.assertPlainDate( + date14430130.with({ monthCode: "M08" }), + 1443, 8, "M08", 29, "29-day Sha'ban constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14430130.with({ monthCode: "M08" }, options); +}, "29-day Sha'ban rejects with 30"); + +TemporalHelpers.assertPlainDate( + date14441230.with({ monthCode: "M09" }), + 1444, 9, "M09", 29, "29-day Ramadan constrains", + "ah", 1444); +assert.throws(RangeError, function () { + date14441230.with({ monthCode: "M09" }, options); +}, "29-day Ramadan rejects with 30"); + +TemporalHelpers.assertPlainDate( + date14420230.with({ monthCode: "M10" }), + 1442, 10, "M10", 29, "29-day Shawwal constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14420230.with({ monthCode: "M10" }, options); +}, "29-day Shawwal rejects with 30"); + +TemporalHelpers.assertPlainDate( + date14441230.with({ monthCode: "M11" }), + 1444, 11, "M11", 29, "29-day Dhu al-Qadah constrains", + "ah", 1444); +assert.throws(RangeError, function () { + date14441230.with({ monthCode: "M11" }, options); +}, "29-day Dhu al-Qadah rejects with 30"); + +TemporalHelpers.assertPlainDate( + date14420230.with({ monthCode: "M12" }), + 1442, 12, "M12", 29, "29-day Dhu al-Hijjah constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14420230.with({ monthCode: "M12" }, options); +}, "29-day Dhu al-Hijjah rejects with 30"); diff --git a/test/intl402/Temporal/PlainDateTime/prototype/add/constrain-day-islamic-umalqura.js b/test/intl402/Temporal/PlainDateTime/prototype/add/constrain-day-islamic-umalqura.js index 31557acaa7..f2320d25b1 100644 --- a/test/intl402/Temporal/PlainDateTime/prototype/add/constrain-day-islamic-umalqura.js +++ b/test/intl402/Temporal/PlainDateTime/prototype/add/constrain-day-islamic-umalqura.js @@ -11,30 +11,282 @@ features: [Temporal, Intl.Era-monthcode] const calendar = "islamic-umalqura"; const options = { overflow: "reject" }; +// Observational month lengths in AH year: +// Y \ M 1 2 3 4 5 6 7 8 9 10 11 12 +// 1442: 29 30 29 30 29 30 29 30 30 29 30 29 +// 1443: 30 29 30 29 30 29 30 29 30 29 30 30 +// 1444: 29 30 29 30 30 29 29 30 29 30 29 30 + // Years +const years1 = new Temporal.Duration(/* years = */ 1); +const years1n = new Temporal.Duration(-1); + +for (const monthCode of ["M01", "M03", "M05", "M07", "M12"]) { + const date1443 = Temporal.PlainDateTime.from({ year: 1443, monthCode, day: 30, hour: 12, minute: 34, calendar }, options); + TemporalHelpers.assertPlainDateTime( + date1443.add(years1n), + 1442, Number(monthCode.slice(1)), monthCode, 29, 12, 34, 0, 0, 0, 0, `Subtracting 1 year from ${monthCode}-30 into 29-day ${monthCode} constrains`, + "ah", 1442 + ); + + assert.throws(RangeError, function () { + date1443.add(years1n, options); + }, `Subtracting 1 year from ${monthCode}-30 into 29-day ${monthCode} rejects`); +} + +for (const monthCode of ["M02", "M04", "M06", "M08"]) { + const date1442 = Temporal.PlainDateTime.from({ year: 1442, monthCode, day: 30, hour: 12, minute: 34, calendar }, options); + TemporalHelpers.assertPlainDateTime( + date1442.add(years1), + 1443, Number(monthCode.slice(1)), monthCode, 29, 12, 34, 0, 0, 0, 0, `Adding 1 year to ${monthCode}-30 into 29-day ${monthCode} constrains`, + "ah", 1443 + ); + + assert.throws(RangeError, function () { + date1442.add(years1, options); + }, `Adding 1 year to ${monthCode}-30 into 29-day ${monthCode} rejects`); +} + +for (const monthCode of ["M09", "M11"]) { + const date1443 = Temporal.PlainDateTime.from({ year: 1443, monthCode, day: 30, hour: 12, minute: 34, calendar }, options); + TemporalHelpers.assertPlainDateTime( + date1443.add(years1), + 1444, Number(monthCode.slice(1)), monthCode, 29, 12, 34, 0, 0, 0, 0, `Adding 1 year to ${monthCode}-30 into 29-day ${monthCode} constrains`, + "ah", 1444 + ); + + assert.throws(RangeError, function () { + date1443.add(years1, options); + }, `Adding 1 year to ${monthCode}-30 into 29-day ${monthCode} rejects`); +} + +const date1444 = Temporal.PlainDateTime.from({ year: 1444, monthCode: "M10", day: 30, hour: 12, minute: 34, calendar }, options); +TemporalHelpers.assertPlainDateTime( + date1444.add(years1n), + 1443, 10, "M10", 29, 12, 34, 0, 0, 0, 0, `Subtracting 1 year from Shawwal 30 into 29-day Shawwal constrains`, + "ah", 1443 +); + +assert.throws(RangeError, function () { + date1444.add(years1n, options); +}, `Subtracting 1 year from Shawwal 30 into 29-day Shawwal rejects`); + // Months const months1 = new Temporal.Duration(0, /* months = */ 1); +const months3 = new Temporal.Duration(0, 3); +const months5 = new Temporal.Duration(0, 5); +const months7 = new Temporal.Duration(0, 7); +const months8 = new Temporal.Duration(0, 8); +const months9 = new Temporal.Duration(0, 9); +const months10 = new Temporal.Duration(0, 10); const months1n = new Temporal.Duration(0, -1); +const months3n = new Temporal.Duration(0, -3); +const months4n = new Temporal.Duration(0, -4); +const months6n = new Temporal.Duration(0, -6); +const months8n = new Temporal.Duration(0, -8); +const months10n = new Temporal.Duration(0, -10); -const date1 = Temporal.PlainDateTime.from({ year: 1447, monthCode: "M01", day: 30, hour: 12, minute: 34, calendar }, options); -TemporalHelpers.assertPlainDateTime( - date1.add(months1), - 1447, 2, "M02", 29, 12, 34, 0, 0, 0, 0, "Day is constrained when adding months to a 30-day month and landing in a 29-day month", - "ah", 1447 -); +const date14420230 = Temporal.PlainDateTime.from({ year: 1442, monthCode: "M02", day: 30, hour: 12, minute: 34, calendar }, options); +const date14430130 = Temporal.PlainDateTime.from({ year: 1443, monthCode: "M01", day: 30, hour: 12, minute: 34, calendar }, options); +const date14440230 = Temporal.PlainDateTime.from({ year: 1444, monthCode: "M02", day: 30, hour: 12, minute: 34, calendar} , options); +const date14421130 = Temporal.PlainDateTime.from({ year: 1442, monthCode: "M11", day: 30, hour: 12, minute: 34, calendar }, options); +const date14431230 = Temporal.PlainDateTime.from({ year: 1443, monthCode: "M12", day: 30, hour: 12, minute: 34, calendar }, options); +const date14441230 = Temporal.PlainDateTime.from({ year: 1444, monthCode: "M12", day: 30, hour: 12, minute: 34, calendar} , options); -assert.throws(RangeError, function () { - date1.add(months1, options); -}, "Adding months to a 30-day month and landing in a 29-day month rejects"); +// Forwards TemporalHelpers.assertPlainDateTime( - date1.add(months1n), - 1446, 12, "M12", 29, 12, 34, 0, 0, 0, 0, "Day is constrained when subtracting months from a 30-day month and landing in a 29-day month", - "ah", 1446 -); - + date14431230.add(months1), + 1444, 1, "M01", 29, 12, 34, 0, 0, 0, 0, "29-day Muharram constrains", + "ah", 1444); assert.throws(RangeError, function () { - date1.add(months1n, options); -}, "Subtracting months from a 30-day month and landing in a 29-day month rejects"); + date14431230.add(months4n, options); +}, "29-day Muharram rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14430130.add(months1), + 1443, 2, "M02", 29, 12, 34, 0, 0, 0, 0, "29-day Safar constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14430130.add(months1, options); +}, "29-day Safar rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14420230.add(months1), + 1442, 3, "M03", 29, 12, 34, 0, 0, 0, 0, "29-day Rabi' al-Awwal constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14420230.add(months1, options); +}, "29-day Rabi' al-Awwal rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14430130.add(months3), + 1443, 4, "M04", 29, 12, 34, 0, 0, 0, 0, "29-day Rabi' al-Thani constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14430130.add(months3, options); +}, "29-day Rabi' al-Thani rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14420230.add(months3), + 1442, 5, "M05", 29, 12, 34, 0, 0, 0, 0, "29-day Jumada al-Awwal constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14420230.add(months3, options); +}, "29-day Jumada al-Awwal rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14430130.add(months5), + 1443, 6, "M06", 29, 12, 34, 0, 0, 0, 0, "29-day Jumada al-Thani constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14430130.add(months5, options); +}, "29-day Jumada al-Thani rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14420230.add(months5), + 1442, 7, "M07", 29, 12, 34, 0, 0, 0, 0, "29-day Rajab constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14420230.add(months5, options); +}, "29-day Rajab rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14430130.add(months7), + 1443, 8, "M08", 29, 12, 34, 0, 0, 0, 0, "29-day Sha'ban constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14430130.add(months7, options); +}, "29-day Sha'ban rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14440230.add(months7), + 1444, 9, "M09", 29, 12, 34, 0, 0, 0, 0, "29-day Ramadan constrains", + "ah", 1444); +assert.throws(RangeError, function () { + date14440230.add(months7, options); +}, "29-day Ramadan rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14420230.add(months8), + 1442, 10, "M10", 29, 12, 34, 0, 0, 0, 0, "29-day Shawwal constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14420230.add(months8, options); +}, "29-day Shawwal rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14440230.add(months9), + 1444, 11, "M11", 29, 12, 34, 0, 0, 0, 0, "29-day Dhu al-Qadah constrains", + "ah", 1444); +assert.throws(RangeError, function () { + date14440230.add(months9, options); +}, "29-day Dhu al-Qadah rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14420230.add(months10), + 1442, 12, "M12", 29, 12, 34, 0, 0, 0, 0, "29-day Dhu al-Hijjah constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14420230.add(months10, options); +}, "29-day Dhu al-Hijjah rejects with 30"); + +// Backwards + +TemporalHelpers.assertPlainDateTime( + date14421130.add(months10n), + 1442, 1, "M01", 29, 12, 34, 0, 0, 0, 0, "29-day Muharram constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14421130.add(months10n, options); +}, "29-day Muharram rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14431230.add(months10n), + 1443, 2, "M02", 29, 12, 34, 0, 0, 0, 0, "29-day Safar constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14431230.add(months10n, options); +}, "29-day Safar rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14421130.add(months8n), + 1442, 3, "M03", 29, 12, 34, 0, 0, 0, 0, "29-day Rabi' al-Awwal constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14421130.add(months8n, options); +}, "29-day Rabi' al-Awwal rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14431230.add(months8n), + 1443, 4, "M04", 29, 12, 34, 0, 0, 0, 0, "29-day Rabi' al-Thani constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14431230.add(months8n, options); +}, "29-day Rabi' al-Thani rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14421130.add(months6n), + 1442, 5, "M05", 29, 12, 34, 0, 0, 0, 0, "29-day Jumada al-Awwal constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14421130.add(months6n, options); +}, "29-day Jumada al-Awwal rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14431230.add(months6n), + 1443, 6, "M06", 29, 12, 34, 0, 0, 0, 0, "29-day Jumada al-Thani constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14431230.add(months6n, options); +}, "29-day Jumada al-Thani rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14421130.add(months4n), + 1442, 7, "M07", 29, 12, 34, 0, 0, 0, 0, "29-day Rajab constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14421130.add(months4n, options); +}, "29-day Rajab rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14431230.add(months4n), + 1443, 8, "M08", 29, 12, 34, 0, 0, 0, 0, "29-day Sha'ban constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14431230.add(months4n, options); +}, "29-day Sha'ban rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14441230.add(months3n), + 1444, 9, "M09", 29, 12, 34, 0, 0, 0, 0, "29-day Ramadan constrains", + "ah", 1444); +assert.throws(RangeError, function () { + date14441230.add(months3n, options); +}, "29-day Ramadan rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14421130.add(months1n), + 1442, 10, "M10", 29, 12, 34, 0, 0, 0, 0, "29-day Shawwal constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14421130.add(months1n, options); +}, "29-day Shawwal rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14441230.add(months1n), + 1444, 11, "M11", 29, 12, 34, 0, 0, 0, 0, "29-day Dhu al-Qadah constrains", + "ah", 1444); +assert.throws(RangeError, function () { + date14441230.add(months1n, options); +}, "29-day Dhu al-Qadah rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14430130.add(months1n), + 1442, 12, "M12", 29, 12, 34, 0, 0, 0, 0, "29-day Dhu al-Hijjah constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14430130.add(months1n, options); +}, "29-day Dhu al-Hijjah rejects with 30"); diff --git a/test/intl402/Temporal/PlainDateTime/prototype/subtract/constrain-day-islamic-umalqura.js b/test/intl402/Temporal/PlainDateTime/prototype/subtract/constrain-day-islamic-umalqura.js index 7d76a8a874..5241c64820 100644 --- a/test/intl402/Temporal/PlainDateTime/prototype/subtract/constrain-day-islamic-umalqura.js +++ b/test/intl402/Temporal/PlainDateTime/prototype/subtract/constrain-day-islamic-umalqura.js @@ -11,30 +11,282 @@ features: [Temporal, Intl.Era-monthcode] const calendar = "islamic-umalqura"; const options = { overflow: "reject" }; +// Observational month lengths in AH year: +// Y \ M 1 2 3 4 5 6 7 8 9 10 11 12 +// 1442: 29 30 29 30 29 30 29 30 30 29 30 29 +// 1443: 30 29 30 29 30 29 30 29 30 29 30 30 +// 1444: 29 30 29 30 30 29 29 30 29 30 29 30 + // Years +const years1 = new Temporal.Duration(/* years = */ -1); +const years1n = new Temporal.Duration(1); + +for (const monthCode of ["M01", "M03", "M05", "M07", "M12"]) { + const date1443 = Temporal.PlainDateTime.from({ year: 1443, monthCode, day: 30, hour: 12, minute: 34, calendar }, options); + TemporalHelpers.assertPlainDateTime( + date1443.subtract(years1n), + 1442, Number(monthCode.slice(1)), monthCode, 29, 12, 34, 0, 0, 0, 0, `Subtracting 1 year from ${monthCode}-30 into 29-day ${monthCode} constrains`, + "ah", 1442 + ); + + assert.throws(RangeError, function () { + date1443.subtract(years1n, options); + }, `Subtracting 1 year from ${monthCode}-30 into 29-day ${monthCode} rejects`); +} + +for (const monthCode of ["M02", "M04", "M06", "M08"]) { + const date1442 = Temporal.PlainDateTime.from({ year: 1442, monthCode, day: 30, hour: 12, minute: 34, calendar }, options); + TemporalHelpers.assertPlainDateTime( + date1442.subtract(years1), + 1443, Number(monthCode.slice(1)), monthCode, 29, 12, 34, 0, 0, 0, 0, `Adding 1 year to ${monthCode}-30 into 29-day ${monthCode} constrains`, + "ah", 1443 + ); + + assert.throws(RangeError, function () { + date1442.subtract(years1, options); + }, `Adding 1 year to ${monthCode}-30 into 29-day ${monthCode} rejects`); +} + +for (const monthCode of ["M09", "M11"]) { + const date1443 = Temporal.PlainDateTime.from({ year: 1443, monthCode, day: 30, hour: 12, minute: 34, calendar }, options); + TemporalHelpers.assertPlainDateTime( + date1443.subtract(years1), + 1444, Number(monthCode.slice(1)), monthCode, 29, 12, 34, 0, 0, 0, 0, `Adding 1 year to ${monthCode}-30 into 29-day ${monthCode} constrains`, + "ah", 1444 + ); + + assert.throws(RangeError, function () { + date1443.subtract(years1, options); + }, `Adding 1 year to ${monthCode}-30 into 29-day ${monthCode} rejects`); +} + +const date1444 = Temporal.PlainDateTime.from({ year: 1444, monthCode: "M10", day: 30, hour: 12, minute: 34, calendar }, options); +TemporalHelpers.assertPlainDateTime( + date1444.subtract(years1n), + 1443, 10, "M10", 29, 12, 34, 0, 0, 0, 0, `Subtracting 1 year from Shawwal 30 into 29-day Shawwal constrains`, + "ah", 1443 +); + +assert.throws(RangeError, function () { + date1444.subtract(years1n, options); +}, `Subtracting 1 year from Shawwal 30 into 29-day Shawwal rejects`); + // Months const months1 = new Temporal.Duration(0, /* months = */ -1); +const months3 = new Temporal.Duration(0, -3); +const months5 = new Temporal.Duration(0, -5); +const months7 = new Temporal.Duration(0, -7); +const months8 = new Temporal.Duration(0, -8); +const months9 = new Temporal.Duration(0, -9); +const months10 = new Temporal.Duration(0, -10); const months1n = new Temporal.Duration(0, 1); +const months3n = new Temporal.Duration(0, 3); +const months4n = new Temporal.Duration(0, 4); +const months6n = new Temporal.Duration(0, 6); +const months8n = new Temporal.Duration(0, 8); +const months10n = new Temporal.Duration(0, 10); -const date1 = Temporal.PlainDateTime.from({ year: 1447, monthCode: "M01", day: 30, hour: 12, minute: 34, calendar }, options); -TemporalHelpers.assertPlainDateTime( - date1.subtract(months1), - 1447, 2, "M02", 29, 12, 34, 0, 0, 0, 0, "Day is constrained when adding months to a 30-day month and landing in a 29-day month", - "ah", 1447 -); +const date14420230 = Temporal.PlainDateTime.from({ year: 1442, monthCode: "M02", day: 30, hour: 12, minute: 34, calendar }, options); +const date14430130 = Temporal.PlainDateTime.from({ year: 1443, monthCode: "M01", day: 30, hour: 12, minute: 34, calendar }, options); +const date14440230 = Temporal.PlainDateTime.from({ year: 1444, monthCode: "M02", day: 30, hour: 12, minute: 34, calendar} , options); +const date14421130 = Temporal.PlainDateTime.from({ year: 1442, monthCode: "M11", day: 30, hour: 12, minute: 34, calendar }, options); +const date14431230 = Temporal.PlainDateTime.from({ year: 1443, monthCode: "M12", day: 30, hour: 12, minute: 34, calendar }, options); +const date14441230 = Temporal.PlainDateTime.from({ year: 1444, monthCode: "M12", day: 30, hour: 12, minute: 34, calendar} , options); -assert.throws(RangeError, function () { - date1.subtract(months1, options); -}, "Adding months to a 30-day month and landing in a 29-day month rejects"); +// Forwards TemporalHelpers.assertPlainDateTime( - date1.subtract(months1n), - 1446, 12, "M12", 29, 12, 34, 0, 0, 0, 0, "Day is constrained when subtracting months from a 30-day month and landing in a 29-day month", - "ah", 1446 -); - + date14431230.subtract(months1), + 1444, 1, "M01", 29, 12, 34, 0, 0, 0, 0, "29-day Muharram constrains", + "ah", 1444); assert.throws(RangeError, function () { - date1.subtract(months1n, options); -}, "Subtracting months from a 30-day month and landing in a 29-day month rejects"); + date14431230.subtract(months4n, options); +}, "29-day Muharram rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14430130.subtract(months1), + 1443, 2, "M02", 29, 12, 34, 0, 0, 0, 0, "29-day Safar constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14430130.subtract(months1, options); +}, "29-day Safar rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14420230.subtract(months1), + 1442, 3, "M03", 29, 12, 34, 0, 0, 0, 0, "29-day Rabi' al-Awwal constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14420230.subtract(months1, options); +}, "29-day Rabi' al-Awwal rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14430130.subtract(months3), + 1443, 4, "M04", 29, 12, 34, 0, 0, 0, 0, "29-day Rabi' al-Thani constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14430130.subtract(months3, options); +}, "29-day Rabi' al-Thani rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14420230.subtract(months3), + 1442, 5, "M05", 29, 12, 34, 0, 0, 0, 0, "29-day Jumada al-Awwal constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14420230.subtract(months3, options); +}, "29-day Jumada al-Awwal rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14430130.subtract(months5), + 1443, 6, "M06", 29, 12, 34, 0, 0, 0, 0, "29-day Jumada al-Thani constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14430130.subtract(months5, options); +}, "29-day Jumada al-Thani rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14420230.subtract(months5), + 1442, 7, "M07", 29, 12, 34, 0, 0, 0, 0, "29-day Rajab constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14420230.subtract(months5, options); +}, "29-day Rajab rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14430130.subtract(months7), + 1443, 8, "M08", 29, 12, 34, 0, 0, 0, 0, "29-day Sha'ban constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14430130.subtract(months7, options); +}, "29-day Sha'ban rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14440230.subtract(months7), + 1444, 9, "M09", 29, 12, 34, 0, 0, 0, 0, "29-day Ramadan constrains", + "ah", 1444); +assert.throws(RangeError, function () { + date14440230.subtract(months7, options); +}, "29-day Ramadan rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14420230.subtract(months8), + 1442, 10, "M10", 29, 12, 34, 0, 0, 0, 0, "29-day Shawwal constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14420230.subtract(months8, options); +}, "29-day Shawwal rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14440230.subtract(months9), + 1444, 11, "M11", 29, 12, 34, 0, 0, 0, 0, "29-day Dhu al-Qadah constrains", + "ah", 1444); +assert.throws(RangeError, function () { + date14440230.subtract(months9, options); +}, "29-day Dhu al-Qadah rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14420230.subtract(months10), + 1442, 12, "M12", 29, 12, 34, 0, 0, 0, 0, "29-day Dhu al-Hijjah constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14420230.subtract(months10, options); +}, "29-day Dhu al-Hijjah rejects with 30"); + +// Backwards + +TemporalHelpers.assertPlainDateTime( + date14421130.subtract(months10n), + 1442, 1, "M01", 29, 12, 34, 0, 0, 0, 0, "29-day Muharram constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14421130.subtract(months10n, options); +}, "29-day Muharram rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14431230.subtract(months10n), + 1443, 2, "M02", 29, 12, 34, 0, 0, 0, 0, "29-day Safar constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14431230.subtract(months10n, options); +}, "29-day Safar rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14421130.subtract(months8n), + 1442, 3, "M03", 29, 12, 34, 0, 0, 0, 0, "29-day Rabi' al-Awwal constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14421130.subtract(months8n, options); +}, "29-day Rabi' al-Awwal rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14431230.subtract(months8n), + 1443, 4, "M04", 29, 12, 34, 0, 0, 0, 0, "29-day Rabi' al-Thani constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14431230.subtract(months8n, options); +}, "29-day Rabi' al-Thani rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14421130.subtract(months6n), + 1442, 5, "M05", 29, 12, 34, 0, 0, 0, 0, "29-day Jumada al-Awwal constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14421130.subtract(months6n, options); +}, "29-day Jumada al-Awwal rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14431230.subtract(months6n), + 1443, 6, "M06", 29, 12, 34, 0, 0, 0, 0, "29-day Jumada al-Thani constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14431230.subtract(months6n, options); +}, "29-day Jumada al-Thani rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14421130.subtract(months4n), + 1442, 7, "M07", 29, 12, 34, 0, 0, 0, 0, "29-day Rajab constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14421130.subtract(months4n, options); +}, "29-day Rajab rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14431230.subtract(months4n), + 1443, 8, "M08", 29, 12, 34, 0, 0, 0, 0, "29-day Sha'ban constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14431230.subtract(months4n, options); +}, "29-day Sha'ban rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14441230.subtract(months3n), + 1444, 9, "M09", 29, 12, 34, 0, 0, 0, 0, "29-day Ramadan constrains", + "ah", 1444); +assert.throws(RangeError, function () { + date14441230.subtract(months3n, options); +}, "29-day Ramadan rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14421130.subtract(months1n), + 1442, 10, "M10", 29, 12, 34, 0, 0, 0, 0, "29-day Shawwal constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14421130.subtract(months1n, options); +}, "29-day Shawwal rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14441230.subtract(months1n), + 1444, 11, "M11", 29, 12, 34, 0, 0, 0, 0, "29-day Dhu al-Qadah constrains", + "ah", 1444); +assert.throws(RangeError, function () { + date14441230.subtract(months1n, options); +}, "29-day Dhu al-Qadah rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14430130.subtract(months1n), + 1442, 12, "M12", 29, 12, 34, 0, 0, 0, 0, "29-day Dhu al-Hijjah constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14430130.subtract(months1n, options); +}, "29-day Dhu al-Hijjah rejects with 30"); diff --git a/test/intl402/Temporal/PlainDateTime/prototype/with/constrain-day-islamic-umalqura.js b/test/intl402/Temporal/PlainDateTime/prototype/with/constrain-day-islamic-umalqura.js new file mode 100644 index 0000000000..3ce6858071 --- /dev/null +++ b/test/intl402/Temporal/PlainDateTime/prototype/with/constrain-day-islamic-umalqura.js @@ -0,0 +1,174 @@ +// Copyright (C) 2025 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.plaindatetime.prototype.with +description: Constraining the day for 29/30-day months in islamic-umalqura calendar +includes: [temporalHelpers.js] +features: [Temporal, Intl.Era-monthcode] +---*/ + +const calendar = "islamic-umalqura"; +const options = { overflow: "reject" }; + +// Observational month lengths in AH year: +// Y \ M 1 2 3 4 5 6 7 8 9 10 11 12 +// 1442: 29 30 29 30 29 30 29 30 30 29 30 29 +// 1443: 30 29 30 29 30 29 30 29 30 29 30 30 +// 1444: 29 30 29 30 30 29 29 30 29 30 29 30 + +// Years + +for (const monthCode of ["M01", "M03", "M05", "M07", "M12"]) { + const date1443 = Temporal.PlainDateTime.from({ year: 1443, monthCode, day: 30, hour: 12, minute: 34, calendar }, options); + TemporalHelpers.assertPlainDateTime( + date1443.with({ year: 1442 }), + 1442, Number(monthCode.slice(1)), monthCode, 29, 12, 34, 0, 0, 0, 0,`Changing the year from ${monthCode}-30 into 29-day ${monthCode} constrains`, + "ah", 1442 + ); + + assert.throws(RangeError, function () { + date1443.with({ year: 1442 }, options); + }, `Changing the year from ${monthCode}-30 into 29-day ${monthCode} rejects`); +} + +for (const monthCode of ["M02", "M04", "M06", "M08"]) { + const date1442 = Temporal.PlainDateTime.from({ year: 1442, monthCode, day: 30, hour: 12, minute: 34, calendar }, options); + TemporalHelpers.assertPlainDateTime( + date1442.with({ year: 1443 }), + 1443, Number(monthCode.slice(1)), monthCode, 29, 12, 34, 0, 0, 0, 0,`Changing the year from ${monthCode}-30 into 29-day ${monthCode} constrains`, + "ah", 1443 + ); + + assert.throws(RangeError, function () { + date1442.with({ year: 1443 }, options); + }, `Changing the year from ${monthCode}-30 into 29-day ${monthCode} rejects`); +} + +for (const monthCode of ["M09", "M11"]) { + const date1443 = Temporal.PlainDateTime.from({ year: 1443, monthCode, day: 30, hour: 12, minute: 34, calendar }, options); + TemporalHelpers.assertPlainDateTime( + date1443.with({ year: 1444 }), + 1444, Number(monthCode.slice(1)), monthCode, 29, 12, 34, 0, 0, 0, 0,`Changing the year from ${monthCode}-30 into 29-day ${monthCode} constrains`, + "ah", 1444 + ); + + assert.throws(RangeError, function () { + date1443.with({ year: 1444 }, options); + }, `Changing the year from ${monthCode}-30 into 29-day ${monthCode} rejects`); +} + +const date1444 = Temporal.PlainDateTime.from({ year: 1444, monthCode: "M10", day: 30, hour: 12, minute: 34, calendar }, options); +TemporalHelpers.assertPlainDateTime( + date1444.with({ year: 1443 }), + 1443, 10, "M10", 29, 12, 34, 0, 0, 0, 0,`Changing the year from Shawwal 30 into 29-day Shawwal constrains`, + "ah", 1443 +); + +assert.throws(RangeError, function () { + date1444.with({ year: 1443 }, options); +}, `Changing the year from Shawwal 30 into 29-day Shawwal rejects`); + +// Months + +const date14420230 = Temporal.PlainDateTime.from({ year: 1442, monthCode: "M02", day: 30, hour: 12, minute: 34, calendar }, options); +const date14430130 = Temporal.PlainDateTime.from({ year: 1443, monthCode: "M01", day: 30, hour: 12, minute: 34, calendar }, options); +const date14441230 = Temporal.PlainDateTime.from({ year: 1444, monthCode: "M12", day: 30, hour: 12, minute: 34, calendar} , options); + +// Forwards + +TemporalHelpers.assertPlainDateTime( + date14441230.with({ monthCode: "M01" }), + 1444, 1, "M01", 29, 12, 34, 0, 0, 0, 0,"29-day Muharram constrains", + "ah", 1444); +assert.throws(RangeError, function () { + date14441230.with({ monthCode: "M01" }, options); +}, "29-day Muharram rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14430130.with({ monthCode: "M02" }), + 1443, 2, "M02", 29, 12, 34, 0, 0, 0, 0,"29-day Safar constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14430130.with({ monthCode: "M02" }, options); +}, "29-day Safar rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14420230.with({ monthCode: "M03" }), + 1442, 3, "M03", 29, 12, 34, 0, 0, 0, 0,"29-day Rabi' al-Awwal constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14420230.with({ monthCode: "M03" }, options); +}, "29-day Rabi' al-Awwal rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14430130.with({ monthCode: "M04" }), + 1443, 4, "M04", 29, 12, 34, 0, 0, 0, 0,"29-day Rabi' al-Thani constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14430130.with({ monthCode: "M04" }, options); +}, "29-day Rabi' al-Thani rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14420230.with({ monthCode: "M05" }), + 1442, 5, "M05", 29, 12, 34, 0, 0, 0, 0,"29-day Jumada al-Awwal constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14420230.with({ monthCode: "M05" }, options); +}, "29-day Jumada al-Awwal rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14430130.with({ monthCode: "M06" }), + 1443, 6, "M06", 29, 12, 34, 0, 0, 0, 0,"29-day Jumada al-Thani constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14430130.with({ monthCode: "M06" }, options); +}, "29-day Jumada al-Thani rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14420230.with({ monthCode: "M07" }), + 1442, 7, "M07", 29, 12, 34, 0, 0, 0, 0,"29-day Rajab constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14420230.with({ monthCode: "M07" }, options); +}, "29-day Rajab rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14430130.with({ monthCode: "M08" }), + 1443, 8, "M08", 29, 12, 34, 0, 0, 0, 0,"29-day Sha'ban constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14430130.with({ monthCode: "M08" }, options); +}, "29-day Sha'ban rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14441230.with({ monthCode: "M09" }), + 1444, 9, "M09", 29, 12, 34, 0, 0, 0, 0,"29-day Ramadan constrains", + "ah", 1444); +assert.throws(RangeError, function () { + date14441230.with({ monthCode: "M09" }, options); +}, "29-day Ramadan rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14420230.with({ monthCode: "M10" }), + 1442, 10, "M10", 29, 12, 34, 0, 0, 0, 0,"29-day Shawwal constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14420230.with({ monthCode: "M10" }, options); +}, "29-day Shawwal rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14441230.with({ monthCode: "M11" }), + 1444, 11, "M11", 29, 12, 34, 0, 0, 0, 0,"29-day Dhu al-Qadah constrains", + "ah", 1444); +assert.throws(RangeError, function () { + date14441230.with({ monthCode: "M11" }, options); +}, "29-day Dhu al-Qadah rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14420230.with({ monthCode: "M12" }), + 1442, 12, "M12", 29, 12, 34, 0, 0, 0, 0,"29-day Dhu al-Hijjah constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14420230.with({ monthCode: "M12" }, options); +}, "29-day Dhu al-Hijjah rejects with 30"); diff --git a/test/intl402/Temporal/ZonedDateTime/prototype/add/constrain-day-islamic-umalqura.js b/test/intl402/Temporal/ZonedDateTime/prototype/add/constrain-day-islamic-umalqura.js index 8cc1b06459..295f31716a 100644 --- a/test/intl402/Temporal/ZonedDateTime/prototype/add/constrain-day-islamic-umalqura.js +++ b/test/intl402/Temporal/ZonedDateTime/prototype/add/constrain-day-islamic-umalqura.js @@ -11,30 +11,282 @@ features: [Temporal, Intl.Era-monthcode] const calendar = "islamic-umalqura"; const options = { overflow: "reject" }; +// Observational month lengths in AH year: +// Y \ M 1 2 3 4 5 6 7 8 9 10 11 12 +// 1442: 29 30 29 30 29 30 29 30 30 29 30 29 +// 1443: 30 29 30 29 30 29 30 29 30 29 30 30 +// 1444: 29 30 29 30 30 29 29 30 29 30 29 30 + // Years +const years1 = new Temporal.Duration(/* years = */ 1); +const years1n = new Temporal.Duration(-1); + +for (const monthCode of ["M01", "M03", "M05", "M07", "M12"]) { + const date1443 = Temporal.ZonedDateTime.from({ year: 1443, monthCode, day: 30, hour: 12, minute: 34, timeZone: "UTC", calendar }, options); + TemporalHelpers.assertPlainDateTime( + date1443.add(years1n).toPlainDateTime(), + 1442, Number(monthCode.slice(1)), monthCode, 29, 12, 34, 0, 0, 0, 0, `Subtracting 1 year from ${monthCode}-30 into 29-day ${monthCode} constrains`, + "ah", 1442 + ); + + assert.throws(RangeError, function () { + date1443.add(years1n, options); + }, `Subtracting 1 year from ${monthCode}-30 into 29-day ${monthCode} rejects`); +} + +for (const monthCode of ["M02", "M04", "M06", "M08"]) { + const date1442 = Temporal.ZonedDateTime.from({ year: 1442, monthCode, day: 30, hour: 12, minute: 34, timeZone: "UTC", calendar }, options); + TemporalHelpers.assertPlainDateTime( + date1442.add(years1).toPlainDateTime(), + 1443, Number(monthCode.slice(1)), monthCode, 29, 12, 34, 0, 0, 0, 0, `Adding 1 year to ${monthCode}-30 into 29-day ${monthCode} constrains`, + "ah", 1443 + ); + + assert.throws(RangeError, function () { + date1442.add(years1, options); + }, `Adding 1 year to ${monthCode}-30 into 29-day ${monthCode} rejects`); +} + +for (const monthCode of ["M09", "M11"]) { + const date1443 = Temporal.ZonedDateTime.from({ year: 1443, monthCode, day: 30, hour: 12, minute: 34, timeZone: "UTC", calendar }, options); + TemporalHelpers.assertPlainDateTime( + date1443.add(years1).toPlainDateTime(), + 1444, Number(monthCode.slice(1)), monthCode, 29, 12, 34, 0, 0, 0, 0, `Adding 1 year to ${monthCode}-30 into 29-day ${monthCode} constrains`, + "ah", 1444 + ); + + assert.throws(RangeError, function () { + date1443.add(years1, options); + }, `Adding 1 year to ${monthCode}-30 into 29-day ${monthCode} rejects`); +} + +const date1444 = Temporal.ZonedDateTime.from({ year: 1444, monthCode: "M10", day: 30, hour: 12, minute: 34, timeZone: "UTC", calendar }, options); +TemporalHelpers.assertPlainDateTime( + date1444.add(years1n).toPlainDateTime(), + 1443, 10, "M10", 29, 12, 34, 0, 0, 0, 0, `Subtracting 1 year from Shawwal 30 into 29-day Shawwal constrains`, + "ah", 1443 +); + +assert.throws(RangeError, function () { + date1444.add(years1n, options); +}, `Subtracting 1 year from Shawwal 30 into 29-day Shawwal rejects`); + // Months const months1 = new Temporal.Duration(0, /* months = */ 1); +const months3 = new Temporal.Duration(0, 3); +const months5 = new Temporal.Duration(0, 5); +const months7 = new Temporal.Duration(0, 7); +const months8 = new Temporal.Duration(0, 8); +const months9 = new Temporal.Duration(0, 9); +const months10 = new Temporal.Duration(0, 10); const months1n = new Temporal.Duration(0, -1); +const months3n = new Temporal.Duration(0, -3); +const months4n = new Temporal.Duration(0, -4); +const months6n = new Temporal.Duration(0, -6); +const months8n = new Temporal.Duration(0, -8); +const months10n = new Temporal.Duration(0, -10); -const date1 = Temporal.ZonedDateTime.from({ year: 1447, monthCode: "M01", day: 30, hour: 12, minute: 34, timeZone: "UTC", calendar }, options); -TemporalHelpers.assertPlainDateTime( - date1.add(months1).toPlainDateTime(), - 1447, 2, "M02", 29, 12, 34, 0, 0, 0, 0, "Day is constrained when adding months to a 30-day month and landing in a 29-day month", - "ah", 1447 -); +const date14420230 = Temporal.ZonedDateTime.from({ year: 1442, monthCode: "M02", day: 30, hour: 12, minute: 34, timeZone: "UTC", calendar }, options); +const date14430130 = Temporal.ZonedDateTime.from({ year: 1443, monthCode: "M01", day: 30, hour: 12, minute: 34, timeZone: "UTC", calendar }, options); +const date14440230 = Temporal.ZonedDateTime.from({ year: 1444, monthCode: "M02", day: 30, hour: 12, minute: 34, timeZone: "UTC", calendar} , options); +const date14421130 = Temporal.ZonedDateTime.from({ year: 1442, monthCode: "M11", day: 30, hour: 12, minute: 34, timeZone: "UTC", calendar }, options); +const date14431230 = Temporal.ZonedDateTime.from({ year: 1443, monthCode: "M12", day: 30, hour: 12, minute: 34, timeZone: "UTC", calendar }, options); +const date14441230 = Temporal.ZonedDateTime.from({ year: 1444, monthCode: "M12", day: 30, hour: 12, minute: 34, timeZone: "UTC", calendar} , options); -assert.throws(RangeError, function () { - date1.add(months1, options); -}, "Adding months to a 30-day month and landing in a 29-day month rejects"); +// Forwards TemporalHelpers.assertPlainDateTime( - date1.add(months1n).toPlainDateTime(), - 1446, 12, "M12", 29, 12, 34, 0, 0, 0, 0, "Day is constrained when subtracting months from a 30-day month and landing in a 29-day month", - "ah", 1446 -); - + date14431230.add(months1).toPlainDateTime(), + 1444, 1, "M01", 29, 12, 34, 0, 0, 0, 0, "29-day Muharram constrains", + "ah", 1444); assert.throws(RangeError, function () { - date1.add(months1n, options); -}, "Subtracting months from a 30-day month and landing in a 29-day month rejects"); + date14431230.add(months4n, options); +}, "29-day Muharram rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14430130.add(months1).toPlainDateTime(), + 1443, 2, "M02", 29, 12, 34, 0, 0, 0, 0, "29-day Safar constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14430130.add(months1, options); +}, "29-day Safar rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14420230.add(months1).toPlainDateTime(), + 1442, 3, "M03", 29, 12, 34, 0, 0, 0, 0, "29-day Rabi' al-Awwal constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14420230.add(months1, options); +}, "29-day Rabi' al-Awwal rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14430130.add(months3).toPlainDateTime(), + 1443, 4, "M04", 29, 12, 34, 0, 0, 0, 0, "29-day Rabi' al-Thani constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14430130.add(months3, options); +}, "29-day Rabi' al-Thani rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14420230.add(months3).toPlainDateTime(), + 1442, 5, "M05", 29, 12, 34, 0, 0, 0, 0, "29-day Jumada al-Awwal constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14420230.add(months3, options); +}, "29-day Jumada al-Awwal rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14430130.add(months5).toPlainDateTime(), + 1443, 6, "M06", 29, 12, 34, 0, 0, 0, 0, "29-day Jumada al-Thani constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14430130.add(months5, options); +}, "29-day Jumada al-Thani rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14420230.add(months5).toPlainDateTime(), + 1442, 7, "M07", 29, 12, 34, 0, 0, 0, 0, "29-day Rajab constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14420230.add(months5, options); +}, "29-day Rajab rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14430130.add(months7).toPlainDateTime(), + 1443, 8, "M08", 29, 12, 34, 0, 0, 0, 0, "29-day Sha'ban constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14430130.add(months7, options); +}, "29-day Sha'ban rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14440230.add(months7).toPlainDateTime(), + 1444, 9, "M09", 29, 12, 34, 0, 0, 0, 0, "29-day Ramadan constrains", + "ah", 1444); +assert.throws(RangeError, function () { + date14440230.add(months7, options); +}, "29-day Ramadan rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14420230.add(months8).toPlainDateTime(), + 1442, 10, "M10", 29, 12, 34, 0, 0, 0, 0, "29-day Shawwal constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14420230.add(months8, options); +}, "29-day Shawwal rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14440230.add(months9).toPlainDateTime(), + 1444, 11, "M11", 29, 12, 34, 0, 0, 0, 0, "29-day Dhu al-Qadah constrains", + "ah", 1444); +assert.throws(RangeError, function () { + date14440230.add(months9, options); +}, "29-day Dhu al-Qadah rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14420230.add(months10).toPlainDateTime(), + 1442, 12, "M12", 29, 12, 34, 0, 0, 0, 0, "29-day Dhu al-Hijjah constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14420230.add(months10, options); +}, "29-day Dhu al-Hijjah rejects with 30"); + +// Backwards + +TemporalHelpers.assertPlainDateTime( + date14421130.add(months10n).toPlainDateTime(), + 1442, 1, "M01", 29, 12, 34, 0, 0, 0, 0, "29-day Muharram constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14421130.add(months10n, options); +}, "29-day Muharram rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14431230.add(months10n).toPlainDateTime(), + 1443, 2, "M02", 29, 12, 34, 0, 0, 0, 0, "29-day Safar constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14431230.add(months10n, options); +}, "29-day Safar rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14421130.add(months8n).toPlainDateTime(), + 1442, 3, "M03", 29, 12, 34, 0, 0, 0, 0, "29-day Rabi' al-Awwal constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14421130.add(months8n, options); +}, "29-day Rabi' al-Awwal rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14431230.add(months8n).toPlainDateTime(), + 1443, 4, "M04", 29, 12, 34, 0, 0, 0, 0, "29-day Rabi' al-Thani constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14431230.add(months8n, options); +}, "29-day Rabi' al-Thani rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14421130.add(months6n).toPlainDateTime(), + 1442, 5, "M05", 29, 12, 34, 0, 0, 0, 0, "29-day Jumada al-Awwal constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14421130.add(months6n, options); +}, "29-day Jumada al-Awwal rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14431230.add(months6n).toPlainDateTime(), + 1443, 6, "M06", 29, 12, 34, 0, 0, 0, 0, "29-day Jumada al-Thani constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14431230.add(months6n, options); +}, "29-day Jumada al-Thani rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14421130.add(months4n).toPlainDateTime(), + 1442, 7, "M07", 29, 12, 34, 0, 0, 0, 0, "29-day Rajab constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14421130.add(months4n, options); +}, "29-day Rajab rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14431230.add(months4n).toPlainDateTime(), + 1443, 8, "M08", 29, 12, 34, 0, 0, 0, 0, "29-day Sha'ban constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14431230.add(months4n, options); +}, "29-day Sha'ban rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14441230.add(months3n).toPlainDateTime(), + 1444, 9, "M09", 29, 12, 34, 0, 0, 0, 0, "29-day Ramadan constrains", + "ah", 1444); +assert.throws(RangeError, function () { + date14441230.add(months3n, options); +}, "29-day Ramadan rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14421130.add(months1n).toPlainDateTime(), + 1442, 10, "M10", 29, 12, 34, 0, 0, 0, 0, "29-day Shawwal constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14421130.add(months1n, options); +}, "29-day Shawwal rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14441230.add(months1n).toPlainDateTime(), + 1444, 11, "M11", 29, 12, 34, 0, 0, 0, 0, "29-day Dhu al-Qadah constrains", + "ah", 1444); +assert.throws(RangeError, function () { + date14441230.add(months1n, options); +}, "29-day Dhu al-Qadah rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14430130.add(months1n).toPlainDateTime(), + 1442, 12, "M12", 29, 12, 34, 0, 0, 0, 0, "29-day Dhu al-Hijjah constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14430130.add(months1n, options); +}, "29-day Dhu al-Hijjah rejects with 30"); diff --git a/test/intl402/Temporal/ZonedDateTime/prototype/subtract/constrain-day-islamic-umalqura.js b/test/intl402/Temporal/ZonedDateTime/prototype/subtract/constrain-day-islamic-umalqura.js index fa75fb0334..56ce7a0898 100644 --- a/test/intl402/Temporal/ZonedDateTime/prototype/subtract/constrain-day-islamic-umalqura.js +++ b/test/intl402/Temporal/ZonedDateTime/prototype/subtract/constrain-day-islamic-umalqura.js @@ -11,30 +11,282 @@ features: [Temporal, Intl.Era-monthcode] const calendar = "islamic-umalqura"; const options = { overflow: "reject" }; +// Observational month lengths in AH year: +// Y \ M 1 2 3 4 5 6 7 8 9 10 11 12 +// 1442: 29 30 29 30 29 30 29 30 30 29 30 29 +// 1443: 30 29 30 29 30 29 30 29 30 29 30 30 +// 1444: 29 30 29 30 30 29 29 30 29 30 29 30 + // Years +const years1 = new Temporal.Duration(/* years = */ -1); +const years1n = new Temporal.Duration(1); + +for (const monthCode of ["M01", "M03", "M05", "M07", "M12"]) { + const date1443 = Temporal.ZonedDateTime.from({ year: 1443, monthCode, day: 30, hour: 12, minute: 34, timeZone: "UTC", calendar }, options); + TemporalHelpers.assertPlainDateTime( + date1443.subtract(years1n).toPlainDateTime(), + 1442, Number(monthCode.slice(1)), monthCode, 29, 12, 34, 0, 0, 0, 0, `Subtracting 1 year from ${monthCode}-30 into 29-day ${monthCode} constrains`, + "ah", 1442 + ); + + assert.throws(RangeError, function () { + date1443.subtract(years1n, options); + }, `Subtracting 1 year from ${monthCode}-30 into 29-day ${monthCode} rejects`); +} + +for (const monthCode of ["M02", "M04", "M06", "M08"]) { + const date1442 = Temporal.ZonedDateTime.from({ year: 1442, monthCode, day: 30, hour: 12, minute: 34, timeZone: "UTC", calendar }, options); + TemporalHelpers.assertPlainDateTime( + date1442.subtract(years1).toPlainDateTime(), + 1443, Number(monthCode.slice(1)), monthCode, 29, 12, 34, 0, 0, 0, 0, `Adding 1 year to ${monthCode}-30 into 29-day ${monthCode} constrains`, + "ah", 1443 + ); + + assert.throws(RangeError, function () { + date1442.subtract(years1, options); + }, `Adding 1 year to ${monthCode}-30 into 29-day ${monthCode} rejects`); +} + +for (const monthCode of ["M09", "M11"]) { + const date1443 = Temporal.ZonedDateTime.from({ year: 1443, monthCode, day: 30, hour: 12, minute: 34, timeZone: "UTC", calendar }, options); + TemporalHelpers.assertPlainDateTime( + date1443.subtract(years1).toPlainDateTime(), + 1444, Number(monthCode.slice(1)), monthCode, 29, 12, 34, 0, 0, 0, 0, `Adding 1 year to ${monthCode}-30 into 29-day ${monthCode} constrains`, + "ah", 1444 + ); + + assert.throws(RangeError, function () { + date1443.subtract(years1, options); + }, `Adding 1 year to ${monthCode}-30 into 29-day ${monthCode} rejects`); +} + +const date1444 = Temporal.ZonedDateTime.from({ year: 1444, monthCode: "M10", day: 30, hour: 12, minute: 34, timeZone: "UTC", calendar }, options); +TemporalHelpers.assertPlainDateTime( + date1444.subtract(years1n).toPlainDateTime(), + 1443, 10, "M10", 29, 12, 34, 0, 0, 0, 0, `Subtracting 1 year from Shawwal 30 into 29-day Shawwal constrains`, + "ah", 1443 +); + +assert.throws(RangeError, function () { + date1444.subtract(years1n, options); +}, `Subtracting 1 year from Shawwal 30 into 29-day Shawwal rejects`); + // Months const months1 = new Temporal.Duration(0, /* months = */ -1); +const months3 = new Temporal.Duration(0, -3); +const months5 = new Temporal.Duration(0, -5); +const months7 = new Temporal.Duration(0, -7); +const months8 = new Temporal.Duration(0, -8); +const months9 = new Temporal.Duration(0, -9); +const months10 = new Temporal.Duration(0, -10); const months1n = new Temporal.Duration(0, 1); +const months3n = new Temporal.Duration(0, 3); +const months4n = new Temporal.Duration(0, 4); +const months6n = new Temporal.Duration(0, 6); +const months8n = new Temporal.Duration(0, 8); +const months10n = new Temporal.Duration(0, 10); -const date1 = Temporal.ZonedDateTime.from({ year: 1447, monthCode: "M01", day: 30, hour: 12, minute: 34, timeZone: "UTC", calendar }, options); -TemporalHelpers.assertPlainDateTime( - date1.subtract(months1).toPlainDateTime(), - 1447, 2, "M02", 29, 12, 34, 0, 0, 0, 0, "Day is constrained when adding months to a 30-day month and landing in a 29-day month", - "ah", 1447 -); +const date14420230 = Temporal.ZonedDateTime.from({ year: 1442, monthCode: "M02", day: 30, hour: 12, minute: 34, timeZone: "UTC", calendar }, options); +const date14430130 = Temporal.ZonedDateTime.from({ year: 1443, monthCode: "M01", day: 30, hour: 12, minute: 34, timeZone: "UTC", calendar }, options); +const date14440230 = Temporal.ZonedDateTime.from({ year: 1444, monthCode: "M02", day: 30, hour: 12, minute: 34, timeZone: "UTC", calendar} , options); +const date14421130 = Temporal.ZonedDateTime.from({ year: 1442, monthCode: "M11", day: 30, hour: 12, minute: 34, timeZone: "UTC", calendar }, options); +const date14431230 = Temporal.ZonedDateTime.from({ year: 1443, monthCode: "M12", day: 30, hour: 12, minute: 34, timeZone: "UTC", calendar }, options); +const date14441230 = Temporal.ZonedDateTime.from({ year: 1444, monthCode: "M12", day: 30, hour: 12, minute: 34, timeZone: "UTC", calendar} , options); -assert.throws(RangeError, function () { - date1.subtract(months1, options); -}, "Adding months to a 30-day month and landing in a 29-day month rejects"); +// Forwards TemporalHelpers.assertPlainDateTime( - date1.subtract(months1n).toPlainDateTime(), - 1446, 12, "M12", 29, 12, 34, 0, 0, 0, 0, "Day is constrained when subtracting months from a 30-day month and landing in a 29-day month", - "ah", 1446 -); - + date14431230.subtract(months1).toPlainDateTime(), + 1444, 1, "M01", 29, 12, 34, 0, 0, 0, 0, "29-day Muharram constrains", + "ah", 1444); assert.throws(RangeError, function () { - date1.subtract(months1n, options); -}, "Subtracting months from a 30-day month and landing in a 29-day month rejects"); + date14431230.subtract(months4n, options); +}, "29-day Muharram rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14430130.subtract(months1).toPlainDateTime(), + 1443, 2, "M02", 29, 12, 34, 0, 0, 0, 0, "29-day Safar constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14430130.subtract(months1, options); +}, "29-day Safar rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14420230.subtract(months1).toPlainDateTime(), + 1442, 3, "M03", 29, 12, 34, 0, 0, 0, 0, "29-day Rabi' al-Awwal constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14420230.subtract(months1, options); +}, "29-day Rabi' al-Awwal rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14430130.subtract(months3).toPlainDateTime(), + 1443, 4, "M04", 29, 12, 34, 0, 0, 0, 0, "29-day Rabi' al-Thani constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14430130.subtract(months3, options); +}, "29-day Rabi' al-Thani rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14420230.subtract(months3).toPlainDateTime(), + 1442, 5, "M05", 29, 12, 34, 0, 0, 0, 0, "29-day Jumada al-Awwal constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14420230.subtract(months3, options); +}, "29-day Jumada al-Awwal rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14430130.subtract(months5).toPlainDateTime(), + 1443, 6, "M06", 29, 12, 34, 0, 0, 0, 0, "29-day Jumada al-Thani constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14430130.subtract(months5, options); +}, "29-day Jumada al-Thani rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14420230.subtract(months5).toPlainDateTime(), + 1442, 7, "M07", 29, 12, 34, 0, 0, 0, 0, "29-day Rajab constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14420230.subtract(months5, options); +}, "29-day Rajab rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14430130.subtract(months7).toPlainDateTime(), + 1443, 8, "M08", 29, 12, 34, 0, 0, 0, 0, "29-day Sha'ban constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14430130.subtract(months7, options); +}, "29-day Sha'ban rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14440230.subtract(months7).toPlainDateTime(), + 1444, 9, "M09", 29, 12, 34, 0, 0, 0, 0, "29-day Ramadan constrains", + "ah", 1444); +assert.throws(RangeError, function () { + date14440230.subtract(months7, options); +}, "29-day Ramadan rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14420230.subtract(months8).toPlainDateTime(), + 1442, 10, "M10", 29, 12, 34, 0, 0, 0, 0, "29-day Shawwal constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14420230.subtract(months8, options); +}, "29-day Shawwal rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14440230.subtract(months9).toPlainDateTime(), + 1444, 11, "M11", 29, 12, 34, 0, 0, 0, 0, "29-day Dhu al-Qadah constrains", + "ah", 1444); +assert.throws(RangeError, function () { + date14440230.subtract(months9, options); +}, "29-day Dhu al-Qadah rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14420230.subtract(months10).toPlainDateTime(), + 1442, 12, "M12", 29, 12, 34, 0, 0, 0, 0, "29-day Dhu al-Hijjah constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14420230.subtract(months10, options); +}, "29-day Dhu al-Hijjah rejects with 30"); + +// Backwards + +TemporalHelpers.assertPlainDateTime( + date14421130.subtract(months10n).toPlainDateTime(), + 1442, 1, "M01", 29, 12, 34, 0, 0, 0, 0, "29-day Muharram constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14421130.subtract(months10n, options); +}, "29-day Muharram rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14431230.subtract(months10n).toPlainDateTime(), + 1443, 2, "M02", 29, 12, 34, 0, 0, 0, 0, "29-day Safar constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14431230.subtract(months10n, options); +}, "29-day Safar rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14421130.subtract(months8n).toPlainDateTime(), + 1442, 3, "M03", 29, 12, 34, 0, 0, 0, 0, "29-day Rabi' al-Awwal constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14421130.subtract(months8n, options); +}, "29-day Rabi' al-Awwal rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14431230.subtract(months8n).toPlainDateTime(), + 1443, 4, "M04", 29, 12, 34, 0, 0, 0, 0, "29-day Rabi' al-Thani constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14431230.subtract(months8n, options); +}, "29-day Rabi' al-Thani rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14421130.subtract(months6n).toPlainDateTime(), + 1442, 5, "M05", 29, 12, 34, 0, 0, 0, 0, "29-day Jumada al-Awwal constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14421130.subtract(months6n, options); +}, "29-day Jumada al-Awwal rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14431230.subtract(months6n).toPlainDateTime(), + 1443, 6, "M06", 29, 12, 34, 0, 0, 0, 0, "29-day Jumada al-Thani constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14431230.subtract(months6n, options); +}, "29-day Jumada al-Thani rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14421130.subtract(months4n).toPlainDateTime(), + 1442, 7, "M07", 29, 12, 34, 0, 0, 0, 0, "29-day Rajab constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14421130.subtract(months4n, options); +}, "29-day Rajab rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14431230.subtract(months4n).toPlainDateTime(), + 1443, 8, "M08", 29, 12, 34, 0, 0, 0, 0, "29-day Sha'ban constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14431230.subtract(months4n, options); +}, "29-day Sha'ban rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14441230.subtract(months3n).toPlainDateTime(), + 1444, 9, "M09", 29, 12, 34, 0, 0, 0, 0, "29-day Ramadan constrains", + "ah", 1444); +assert.throws(RangeError, function () { + date14441230.subtract(months3n, options); +}, "29-day Ramadan rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14421130.subtract(months1n).toPlainDateTime(), + 1442, 10, "M10", 29, 12, 34, 0, 0, 0, 0, "29-day Shawwal constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14421130.subtract(months1n, options); +}, "29-day Shawwal rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14441230.subtract(months1n).toPlainDateTime(), + 1444, 11, "M11", 29, 12, 34, 0, 0, 0, 0, "29-day Dhu al-Qadah constrains", + "ah", 1444); +assert.throws(RangeError, function () { + date14441230.subtract(months1n, options); +}, "29-day Dhu al-Qadah rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14430130.subtract(months1n).toPlainDateTime(), + 1442, 12, "M12", 29, 12, 34, 0, 0, 0, 0, "29-day Dhu al-Hijjah constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14430130.subtract(months1n, options); +}, "29-day Dhu al-Hijjah rejects with 30"); diff --git a/test/intl402/Temporal/ZonedDateTime/prototype/with/constrain-day-islamic-umalqura.js b/test/intl402/Temporal/ZonedDateTime/prototype/with/constrain-day-islamic-umalqura.js new file mode 100644 index 0000000000..dddb278c49 --- /dev/null +++ b/test/intl402/Temporal/ZonedDateTime/prototype/with/constrain-day-islamic-umalqura.js @@ -0,0 +1,174 @@ +// Copyright (C) 2025 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +esid: sec-temporal.zoneddatetime.prototype.with +description: Constraining the day for 29/30-day months in islamic-umalqura calendar +includes: [temporalHelpers.js] +features: [Temporal, Intl.Era-monthcode] +---*/ + +const calendar = "islamic-umalqura"; +const options = { overflow: "reject" }; + +// Observational month lengths in AH year: +// Y \ M 1 2 3 4 5 6 7 8 9 10 11 12 +// 1442: 29 30 29 30 29 30 29 30 30 29 30 29 +// 1443: 30 29 30 29 30 29 30 29 30 29 30 30 +// 1444: 29 30 29 30 30 29 29 30 29 30 29 30 + +// Years + +for (const monthCode of ["M01", "M03", "M05", "M07", "M12"]) { + const date1443 = Temporal.ZonedDateTime.from({ year: 1443, monthCode, day: 30, hour: 12, minute: 34, timeZone: "UTC", calendar }, options); + TemporalHelpers.assertPlainDateTime( + date1443.with({ year: 1442 }).toPlainDateTime(), + 1442, Number(monthCode.slice(1)), monthCode, 29, 12, 34, 0, 0, 0, 0,`Changing the year from ${monthCode}-30 into 29-day ${monthCode} constrains`, + "ah", 1442 + ); + + assert.throws(RangeError, function () { + date1443.with({ year: 1442 }, options); + }, `Changing the year from ${monthCode}-30 into 29-day ${monthCode} rejects`); +} + +for (const monthCode of ["M02", "M04", "M06", "M08"]) { + const date1442 = Temporal.ZonedDateTime.from({ year: 1442, monthCode, day: 30, hour: 12, minute: 34, timeZone: "UTC", calendar }, options); + TemporalHelpers.assertPlainDateTime( + date1442.with({ year: 1443 }).toPlainDateTime(), + 1443, Number(monthCode.slice(1)), monthCode, 29, 12, 34, 0, 0, 0, 0,`Changing the year from ${monthCode}-30 into 29-day ${monthCode} constrains`, + "ah", 1443 + ); + + assert.throws(RangeError, function () { + date1442.with({ year: 1443 }, options); + }, `Changing the year from ${monthCode}-30 into 29-day ${monthCode} rejects`); +} + +for (const monthCode of ["M09", "M11"]) { + const date1443 = Temporal.ZonedDateTime.from({ year: 1443, monthCode, day: 30, hour: 12, minute: 34, timeZone: "UTC", calendar }, options); + TemporalHelpers.assertPlainDateTime( + date1443.with({ year: 1444 }).toPlainDateTime(), + 1444, Number(monthCode.slice(1)), monthCode, 29, 12, 34, 0, 0, 0, 0,`Changing the year from ${monthCode}-30 into 29-day ${monthCode} constrains`, + "ah", 1444 + ); + + assert.throws(RangeError, function () { + date1443.with({ year: 1444 }, options); + }, `Changing the year from ${monthCode}-30 into 29-day ${monthCode} rejects`); +} + +const date1444 = Temporal.ZonedDateTime.from({ year: 1444, monthCode: "M10", day: 30, hour: 12, minute: 34, timeZone: "UTC", calendar }, options); +TemporalHelpers.assertPlainDateTime( + date1444.with({ year: 1443 }).toPlainDateTime(), + 1443, 10, "M10", 29, 12, 34, 0, 0, 0, 0,`Changing the year from Shawwal 30 into 29-day Shawwal constrains`, + "ah", 1443 +); + +assert.throws(RangeError, function () { + date1444.with({ year: 1443 }, options); +}, `Changing the year from Shawwal 30 into 29-day Shawwal rejects`); + +// Months + +const date14420230 = Temporal.ZonedDateTime.from({ year: 1442, monthCode: "M02", day: 30, hour: 12, minute: 34, timeZone: "UTC", calendar }, options); +const date14430130 = Temporal.ZonedDateTime.from({ year: 1443, monthCode: "M01", day: 30, hour: 12, minute: 34, timeZone: "UTC", calendar }, options); +const date14441230 = Temporal.ZonedDateTime.from({ year: 1444, monthCode: "M12", day: 30, hour: 12, minute: 34, timeZone: "UTC", calendar} , options); + +// Forwards + +TemporalHelpers.assertPlainDateTime( + date14441230.with({ monthCode: "M01" }).toPlainDateTime(), + 1444, 1, "M01", 29, 12, 34, 0, 0, 0, 0,"29-day Muharram constrains", + "ah", 1444); +assert.throws(RangeError, function () { + date14441230.with({ monthCode: "M01" }, options); +}, "29-day Muharram rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14430130.with({ monthCode: "M02" }).toPlainDateTime(), + 1443, 2, "M02", 29, 12, 34, 0, 0, 0, 0,"29-day Safar constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14430130.with({ monthCode: "M02" }, options); +}, "29-day Safar rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14420230.with({ monthCode: "M03" }).toPlainDateTime(), + 1442, 3, "M03", 29, 12, 34, 0, 0, 0, 0,"29-day Rabi' al-Awwal constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14420230.with({ monthCode: "M03" }, options); +}, "29-day Rabi' al-Awwal rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14430130.with({ monthCode: "M04" }).toPlainDateTime(), + 1443, 4, "M04", 29, 12, 34, 0, 0, 0, 0,"29-day Rabi' al-Thani constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14430130.with({ monthCode: "M04" }, options); +}, "29-day Rabi' al-Thani rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14420230.with({ monthCode: "M05" }).toPlainDateTime(), + 1442, 5, "M05", 29, 12, 34, 0, 0, 0, 0,"29-day Jumada al-Awwal constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14420230.with({ monthCode: "M05" }, options); +}, "29-day Jumada al-Awwal rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14430130.with({ monthCode: "M06" }).toPlainDateTime(), + 1443, 6, "M06", 29, 12, 34, 0, 0, 0, 0,"29-day Jumada al-Thani constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14430130.with({ monthCode: "M06" }, options); +}, "29-day Jumada al-Thani rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14420230.with({ monthCode: "M07" }).toPlainDateTime(), + 1442, 7, "M07", 29, 12, 34, 0, 0, 0, 0,"29-day Rajab constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14420230.with({ monthCode: "M07" }, options); +}, "29-day Rajab rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14430130.with({ monthCode: "M08" }).toPlainDateTime(), + 1443, 8, "M08", 29, 12, 34, 0, 0, 0, 0,"29-day Sha'ban constrains", + "ah", 1443); +assert.throws(RangeError, function () { + date14430130.with({ monthCode: "M08" }, options); +}, "29-day Sha'ban rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14441230.with({ monthCode: "M09" }).toPlainDateTime(), + 1444, 9, "M09", 29, 12, 34, 0, 0, 0, 0,"29-day Ramadan constrains", + "ah", 1444); +assert.throws(RangeError, function () { + date14441230.with({ monthCode: "M09" }, options); +}, "29-day Ramadan rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14420230.with({ monthCode: "M10" }).toPlainDateTime(), + 1442, 10, "M10", 29, 12, 34, 0, 0, 0, 0,"29-day Shawwal constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14420230.with({ monthCode: "M10" }, options); +}, "29-day Shawwal rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14441230.with({ monthCode: "M11" }).toPlainDateTime(), + 1444, 11, "M11", 29, 12, 34, 0, 0, 0, 0,"29-day Dhu al-Qadah constrains", + "ah", 1444); +assert.throws(RangeError, function () { + date14441230.with({ monthCode: "M11" }, options); +}, "29-day Dhu al-Qadah rejects with 30"); + +TemporalHelpers.assertPlainDateTime( + date14420230.with({ monthCode: "M12" }).toPlainDateTime(), + 1442, 12, "M12", 29, 12, 34, 0, 0, 0, 0,"29-day Dhu al-Hijjah constrains", + "ah", 1442); +assert.throws(RangeError, function () { + date14420230.with({ monthCode: "M12" }, options); +}, "29-day Dhu al-Hijjah rejects with 30");