summaryrefslogtreecommitdiffstats
path: root/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth')
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-builtin-calendar-no-array-iteration.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-calendar-datefromfields-called-with-null-prototype-fields.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-constructor-in-calendar-fields.js17
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-duplicate-calendar-fields.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-leap-second.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-number.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-propertybag-calendar-case-insensitive.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-propertybag-calendar-leap-second.js23
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-propertybag-calendar-number.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-propertybag-calendar-string.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-propertybag-calendar-wrong-type.js46
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-propertybag-calendar-year-zero.js27
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-proto-in-calendar-fields.js17
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-calendar-annotation.js33
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-critical-unknown-annotation.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-date-with-utc-offset.js48
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-invalid.js64
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-multiple-calendar.js32
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-multiple-time-zone.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-time-separators.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-time-zone-annotation.js38
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-unknown-annotation.js32
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-with-utc-designator.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-wrong-type.js43
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-convert.js22
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-slots.js40
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js23
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/basic.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/branding.js27
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/browser.js0
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/builtin.js36
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/calendar-datefromfields-called-with-options-undefined.js18
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/calendar-fields-iterable.js35
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/calendar-temporal-object.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/infinity-throws-rangeerror.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/length.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/name.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/not-a-constructor.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/plain-date-time.js116
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/plain-date.js58
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/prop-desc.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/shell.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/string.js35
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/throw-range-error-ToTemporalDate.js21
-rw-r--r--js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/year-zero.js26
48 files changed, 1438 insertions, 0 deletions
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-builtin-calendar-no-array-iteration.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-builtin-calendar-no-array-iteration.js
new file mode 100644
index 0000000000..319534ca4f
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-builtin-calendar-no-array-iteration.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: >
+ Calling the method with a property bag argument with a builtin calendar causes
+ no observable array iteration when getting the calendar fields.
+features: [Temporal]
+---*/
+
+const arrayPrototypeSymbolIteratorOriginal = Array.prototype[Symbol.iterator];
+Array.prototype[Symbol.iterator] = function arrayIterator() {
+ throw new Test262Error("Array should not be iterated");
+}
+
+const instance = new Temporal.Calendar("iso8601");
+const arg = { year: 2000, month: 5, day: 2, calendar: "iso8601" };
+instance.daysInMonth(arg);
+
+Array.prototype[Symbol.iterator] = arrayPrototypeSymbolIteratorOriginal;
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-calendar-datefromfields-called-with-null-prototype-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-calendar-datefromfields-called-with-null-prototype-fields.js
new file mode 100644
index 0000000000..1198405424
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-calendar-datefromfields-called-with-null-prototype-fields.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: >
+ Calendar.dateFromFields method is called with a null-prototype fields object
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarCheckFieldsPrototypePollution();
+const instance = new Temporal.Calendar("iso8601");
+const arg = { year: 2000, month: 5, day: 2, calendar };
+instance.daysInMonth(arg);
+assert.sameValue(calendar.dateFromFieldsCallCount, 1, "dateFromFields should be called on the property bag's calendar");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-constructor-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-constructor-in-calendar-fields.js
new file mode 100644
index 0000000000..50db14415b
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-constructor-in-calendar-fields.js
@@ -0,0 +1,17 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: If a calendar's fields() method returns a field named 'constructor', PrepareTemporalFields should throw a RangeError.
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarWithExtraFields(['constructor']);
+const arg = {year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar};
+const instance = new Temporal.Calendar("iso8601");
+
+assert.throws(RangeError, () => instance.daysInMonth(arg));
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-duplicate-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-duplicate-calendar-fields.js
new file mode 100644
index 0000000000..d183b4ee69
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-duplicate-calendar-fields.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: If a calendar's fields() method returns duplicate field names, PrepareTemporalFields should throw a RangeError.
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+for (const extra_fields of [['foo', 'foo'], ['day'], ['month'], ['monthCode'], ['year']]) {
+ const calendar = TemporalHelpers.calendarWithExtraFields(extra_fields);
+ const arg = { year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar };
+ const instance = new Temporal.Calendar("iso8601");
+
+ assert.throws(RangeError, () => instance.daysInMonth(arg));
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-leap-second.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-leap-second.js
new file mode 100644
index 0000000000..30e56f42b2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-leap-second.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: Leap second is a valid ISO string for PlainDate
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+let arg = "2016-12-31T23:59:60";
+const result1 = instance.daysInMonth(arg);
+assert.sameValue(
+ result1,
+ 31,
+ "leap second is a valid ISO string for PlainDate"
+);
+
+arg = { year: 2016, month: 12, day: 31, hour: 23, minute: 59, second: 60 };
+const result2 = instance.daysInMonth(arg);
+assert.sameValue(
+ result2,
+ 31,
+ "second: 60 is ignored in property bag for PlainDate"
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-number.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-number.js
new file mode 100644
index 0000000000..e2f40427c9
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-number.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: A number cannot be used in place of a Temporal.PlainDate
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const numbers = [
+ 1,
+ 19761118,
+ -19761118,
+ 1234567890,
+];
+
+for (const arg of numbers) {
+ assert.throws(
+ TypeError,
+ () => instance.daysInMonth(arg),
+ 'Numbers cannot be used in place of an ISO string for PlainDate'
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-propertybag-calendar-case-insensitive.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-propertybag-calendar-case-insensitive.js
new file mode 100644
index 0000000000..bcda4dbf08
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-propertybag-calendar-case-insensitive.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: The calendar name is case-insensitive
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const calendar = "IsO8601";
+
+const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+const result = instance.daysInMonth(arg);
+assert.sameValue(result, 30, "Calendar is case-insensitive");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-propertybag-calendar-leap-second.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-propertybag-calendar-leap-second.js
new file mode 100644
index 0000000000..bd6efd827b
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-propertybag-calendar-leap-second.js
@@ -0,0 +1,23 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: Leap second is a valid ISO string for a calendar in a property bag
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const calendar = "2016-12-31T23:59:60";
+
+const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+const result = instance.daysInMonth(arg);
+assert.sameValue(
+ result,
+ 30,
+ "leap second is a valid ISO string for calendar"
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-propertybag-calendar-number.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-propertybag-calendar-number.js
new file mode 100644
index 0000000000..4a2e0fe015
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-propertybag-calendar-number.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: A number as calendar in a property bag is not accepted
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const numbers = [
+ 1,
+ 19970327,
+ -19970327,
+ 1234567890,
+];
+
+for (const calendar of numbers) {
+ const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+ assert.throws(
+ TypeError,
+ () => instance.daysInMonth(arg),
+ "Numbers cannot be used as a calendar"
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-propertybag-calendar-string.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-propertybag-calendar-string.js
new file mode 100644
index 0000000000..8f207d8388
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-propertybag-calendar-string.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: A calendar ID is valid input for Calendar
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const calendar = "iso8601";
+
+const arg = { year: 1976, monthCode: "M11", day: 18, calendar };
+const result = instance.daysInMonth(arg);
+assert.sameValue(result, 30, `Calendar created from string "${calendar}"`);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-propertybag-calendar-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-propertybag-calendar-wrong-type.js
new file mode 100644
index 0000000000..beb74d902f
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-propertybag-calendar-wrong-type.js
@@ -0,0 +1,46 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: >
+ Appropriate error thrown when a calendar property from a property bag cannot
+ be converted to a calendar object or string
+features: [BigInt, Symbol, Temporal]
+---*/
+
+const timeZone = new Temporal.TimeZone("UTC");
+const instance = new Temporal.Calendar("iso8601");
+
+const primitiveTests = [
+ [null, "null"],
+ [true, "boolean"],
+ ["", "empty string"],
+ [1, "number that doesn't convert to a valid ISO string"],
+ [1n, "bigint"],
+];
+
+for (const [calendar, description] of primitiveTests) {
+ const arg = { year: 2019, monthCode: "M11", day: 1, calendar };
+ assert.throws(
+ typeof calendar === 'string' ? RangeError : TypeError,
+ () => instance.daysInMonth(arg),
+ `${description} does not convert to a valid ISO string`
+ );
+}
+
+const typeErrorTests = [
+ [Symbol(), "symbol"],
+ [{}, "plain object that doesn't implement the protocol"],
+ [new Temporal.TimeZone("UTC"), "time zone instance"],
+ [Temporal.Calendar, "Temporal.Calendar, object"],
+ [Temporal.Calendar.prototype, "Temporal.Calendar.prototype, object"], // fails brand check in dateFromFields()
+];
+
+for (const [calendar, description] of typeErrorTests) {
+ const arg = { year: 2019, monthCode: "M11", day: 1, calendar };
+ assert.throws(TypeError, () => instance.daysInMonth(arg), `${description} is not a valid property bag and does not convert to a string`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-propertybag-calendar-year-zero.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-propertybag-calendar-year-zero.js
new file mode 100644
index 0000000000..8a6f651473
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-propertybag-calendar-year-zero.js
@@ -0,0 +1,27 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: Negative zero, as an extended year, is rejected
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ "-000000-10-31",
+ "-000000-10-31T17:45",
+ "-000000-10-31T17:45Z",
+ "-000000-10-31T17:45+01:00",
+ "-000000-10-31T17:45+00:00[UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.daysInMonth(arg),
+ "reject minus zero as extended year"
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-proto-in-calendar-fields.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-proto-in-calendar-fields.js
new file mode 100644
index 0000000000..54de92486e
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-proto-in-calendar-fields.js
@@ -0,0 +1,17 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: If a calendar's fields() method returns a field named '__proto__', PrepareTemporalFields should throw a RangeError.
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarWithExtraFields(['__proto__']);
+const arg = {year: 2023, month: 5, monthCode: 'M05', day: 1, calendar: calendar};
+const instance = new Temporal.Calendar("iso8601");
+
+assert.throws(RangeError, () => instance.daysInMonth(arg));
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-calendar-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-calendar-annotation.js
new file mode 100644
index 0000000000..4a0ed3ba9f
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-calendar-annotation.js
@@ -0,0 +1,33 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: Various forms of calendar annotation; critical flag has no effect
+features: [Temporal]
+---*/
+
+const tests = [
+ ["2000-05-02[u-ca=iso8601]", "without time or time zone"],
+ ["2000-05-02[UTC][u-ca=iso8601]", "with time zone and no time"],
+ ["2000-05-02T15:23[u-ca=iso8601]", "without time zone"],
+ ["2000-05-02T15:23[UTC][u-ca=iso8601]", "with time zone"],
+ ["2000-05-02T15:23[!u-ca=iso8601]", "with ! and no time zone"],
+ ["2000-05-02T15:23[UTC][!u-ca=iso8601]", "with ! and time zone"],
+ ["2000-05-02T15:23[u-ca=iso8601][u-ca=discord]", "second annotation ignored"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.daysInMonth(arg);
+
+ assert.sameValue(
+ result,
+ 31,
+ `calendar annotation (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-critical-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-critical-unknown-annotation.js
new file mode 100644
index 0000000000..fd0f58ec15
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-critical-unknown-annotation.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: Unknown annotations with critical flag are rejected
+features: [Temporal]
+---*/
+
+const invalidStrings = [
+ "1970-01-01[!foo=bar]",
+ "1970-01-01T00:00[!foo=bar]",
+ "1970-01-01T00:00[UTC][!foo=bar]",
+ "1970-01-01T00:00[u-ca=iso8601][!foo=bar]",
+ "1970-01-01T00:00[UTC][!foo=bar][u-ca=iso8601]",
+ "1970-01-01T00:00[foo=bar][!_foo-bar0=Dont-Ignore-This-99999999999]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.daysInMonth(arg),
+ `reject unknown annotation with critical flag: ${arg}`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-date-with-utc-offset.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-date-with-utc-offset.js
new file mode 100644
index 0000000000..8a7a746a83
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-date-with-utc-offset.js
@@ -0,0 +1,48 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: UTC offset not valid with format that does not include a time
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const validStrings = [
+ "2000-05-02T00+00:00",
+ "2000-05-02T00+00:00[UTC]",
+ "2000-05-02T00+00:00[!UTC]",
+ "2000-05-02T00-02:30[America/St_Johns]",
+];
+
+for (const arg of validStrings) {
+ const result = instance.daysInMonth(arg);
+
+ assert.sameValue(
+ result,
+ 31,
+ `"${arg}" is a valid UTC offset with time for PlainDate`
+ );
+}
+
+const invalidStrings = [
+ "2022-09-15Z",
+ "2022-09-15Z[UTC]",
+ "2022-09-15Z[Europe/Vienna]",
+ "2022-09-15+00:00",
+ "2022-09-15+00:00[UTC]",
+ "2022-09-15-02:30",
+ "2022-09-15-02:30[America/St_Johns]",
+];
+
+for (const arg of invalidStrings) {
+ assert.throws(
+ RangeError,
+ () => instance.daysInMonth(arg),
+ `"${arg}" UTC offset without time is not valid for PlainDate`
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-invalid.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-invalid.js
new file mode 100644
index 0000000000..5d4b66354e
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-invalid.js
@@ -0,0 +1,64 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: >
+ RangeError thrown if an invalid ISO string (or syntactically valid ISO string
+ that is not supported) is used as a PlainDate
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ // invalid ISO strings:
+ "",
+ "invalid iso8601",
+ "2020-01-00",
+ "2020-01-32",
+ "2020-02-30",
+ "2021-02-29",
+ "2020-00-01",
+ "2020-13-01",
+ "2020-01-01T",
+ "2020-01-01T25:00:00",
+ "2020-01-01T01:60:00",
+ "2020-01-01T01:60:61",
+ "2020-01-01junk",
+ "2020-01-01T00:00:00junk",
+ "2020-01-01T00:00:00+00:00junk",
+ "2020-01-01T00:00:00+00:00[UTC]junk",
+ "2020-01-01T00:00:00+00:00[UTC][u-ca=iso8601]junk",
+ "02020-01-01",
+ "2020-001-01",
+ "2020-01-001",
+ "2020-01-01T001",
+ "2020-01-01T01:001",
+ "2020-01-01T01:01:001",
+ // valid, but forms not supported in Temporal:
+ "2020-W01-1",
+ "2020-001",
+ "+0002020-01-01",
+ // valid, but this calendar must not exist:
+ "2020-01-01[u-ca=notexist]",
+ // may be valid in other contexts, but insufficient information for PlainDate:
+ "2020-01",
+ "+002020-01",
+ "01-01",
+ "2020-W01",
+ "P1Y",
+ "-P12Y",
+ // valid, but outside the supported range:
+ "-999999-01-01",
+ "+999999-01-01",
+];
+const instance = new Temporal.Calendar("iso8601");
+for (const arg of invalidStrings) {
+ assert.throws(
+ RangeError,
+ () => instance.daysInMonth(arg),
+ `"${arg}" should not be a valid ISO string for a PlainDate`
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-multiple-calendar.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-multiple-calendar.js
new file mode 100644
index 0000000000..a6b940ebf0
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-multiple-calendar.js
@@ -0,0 +1,32 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2023 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: >
+ More than one calendar annotation is not syntactical if any have the criical
+ flag
+features: [Temporal]
+---*/
+
+const invalidStrings = [
+ "1970-01-01[u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01[!u-ca=iso8601][u-ca=iso8601]",
+ "1970-01-01[UTC][u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01[u-ca=iso8601][foo=bar][!u-ca=iso8601]",
+ "1970-01-01T00:00[u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01T00:00[!u-ca=iso8601][u-ca=iso8601]",
+ "1970-01-01T00:00[UTC][u-ca=iso8601][!u-ca=iso8601]",
+ "1970-01-01T00:00[u-ca=iso8601][foo=bar][!u-ca=iso8601]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.daysInMonth(arg),
+ `reject more than one calendar annotation if any critical: ${arg}`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-multiple-time-zone.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-multiple-time-zone.js
new file mode 100644
index 0000000000..5087ca2fe5
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-multiple-time-zone.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: More than one time zone annotation is not syntactical
+features: [Temporal]
+---*/
+
+const invalidStrings = [
+ "1970-01-01[UTC][UTC]",
+ "1970-01-01T00:00[UTC][UTC]",
+ "1970-01-01T00:00[!UTC][UTC]",
+ "1970-01-01T00:00[UTC][!UTC]",
+ "1970-01-01T00:00[UTC][u-ca=iso8601][UTC]",
+ "1970-01-01T00:00[UTC][foo=bar][UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.daysInMonth(arg),
+ `reject more than one time zone annotation: ${arg}`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-time-separators.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-time-separators.js
new file mode 100644
index 0000000000..049dd56d85
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-time-separators.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: Time separator in string argument can vary
+features: [Temporal]
+---*/
+
+const tests = [
+ ["2000-05-02T15:23", "uppercase T"],
+ ["2000-05-02t15:23", "lowercase T"],
+ ["2000-05-02 15:23", "space between date and time"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.daysInMonth(arg);
+
+ assert.sameValue(
+ result,
+ 31,
+ `variant time separators (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-time-zone-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-time-zone-annotation.js
new file mode 100644
index 0000000000..7432b240c0
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-time-zone-annotation.js
@@ -0,0 +1,38 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: Various forms of time zone annotation; critical flag has no effect
+features: [Temporal]
+---*/
+
+const tests = [
+ ["2000-05-02[Asia/Kolkata]", "named, with no time"],
+ ["2000-05-02[!Europe/Vienna]", "named, with ! and no time"],
+ ["2000-05-02[+00:00]", "numeric, with no time"],
+ ["2000-05-02[!-02:30]", "numeric, with ! and no time"],
+ ["2000-05-02T15:23[America/Sao_Paulo]", "named, with no offset"],
+ ["2000-05-02T15:23[!Asia/Tokyo]", "named, with ! and no offset"],
+ ["2000-05-02T15:23[-02:30]", "numeric, with no offset"],
+ ["2000-05-02T15:23[!+00:00]", "numeric, with ! and no offset"],
+ ["2000-05-02T15:23+00:00[America/New_York]", "named, with offset"],
+ ["2000-05-02T15:23+00:00[!UTC]", "named, with offset and !"],
+ ["2000-05-02T15:23+00:00[+01:00]", "numeric, with offset"],
+ ["2000-05-02T15:23+00:00[!-08:00]", "numeric, with offset and !"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.daysInMonth(arg);
+
+ assert.sameValue(
+ result,
+ 31,
+ `time zone annotation (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-unknown-annotation.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-unknown-annotation.js
new file mode 100644
index 0000000000..7b9329b45f
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-unknown-annotation.js
@@ -0,0 +1,32 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: Various forms of unknown annotation
+features: [Temporal]
+---*/
+
+const tests = [
+ ["2000-05-02[foo=bar]", "without time"],
+ ["2000-05-02T15:23[foo=bar]", "alone"],
+ ["2000-05-02T15:23[UTC][foo=bar]", "with time zone"],
+ ["2000-05-02T15:23[u-ca=iso8601][foo=bar]", "with calendar"],
+ ["2000-05-02T15:23[UTC][foo=bar][u-ca=iso8601]", "with time zone and calendar"],
+ ["2000-05-02T15:23[foo=bar][_foo-bar0=Ignore-This-999999999999]", "with another unknown annotation"],
+];
+
+const instance = new Temporal.Calendar("iso8601");
+
+tests.forEach(([arg, description]) => {
+ const result = instance.daysInMonth(arg);
+
+ assert.sameValue(
+ result,
+ 31,
+ `unknown annotation (${description})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-with-utc-designator.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-with-utc-designator.js
new file mode 100644
index 0000000000..2f221212ea
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-string-with-utc-designator.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: RangeError thrown if a string with UTC designator is used as a PlainDate
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ "2019-10-01T09:00:00Z",
+ "2019-10-01T09:00:00Z[UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.daysInMonth(arg),
+ "String with UTC designator should not be valid as a PlainDate"
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-wrong-type.js
new file mode 100644
index 0000000000..074c5479f8
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-wrong-type.js
@@ -0,0 +1,43 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: >
+ Appropriate error thrown when argument cannot be converted to a valid string
+ or property bag for PlainDate
+features: [BigInt, Symbol, Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+
+const primitiveTests = [
+ [undefined, "undefined"],
+ [null, "null"],
+ [true, "boolean"],
+ ["", "empty string"],
+ [1, "number that doesn't convert to a valid ISO string"],
+ [1n, "bigint"],
+];
+
+for (const [arg, description] of primitiveTests) {
+ assert.throws(
+ typeof arg === 'string' ? RangeError : TypeError,
+ () => instance.daysInMonth(arg),
+ `${description} does not convert to a valid ISO string`
+ );
+}
+
+const typeErrorTests = [
+ [Symbol(), "symbol"],
+ [{}, "plain object"],
+ [Temporal.PlainDate, "Temporal.PlainDate, object"],
+ [Temporal.PlainDate.prototype, "Temporal.PlainDate.prototype, object"],
+];
+
+for (const [arg, description] of typeErrorTests) {
+ assert.throws(TypeError, () => instance.daysInMonth(arg), `${description} is not a valid property bag and does not convert to a string`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-convert.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-convert.js
new file mode 100644
index 0000000000..4d826cd5b7
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-convert.js
@@ -0,0 +1,22 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: An exception from TimeZone#getOffsetNanosecondsFor() is propagated.
+features: [Temporal]
+---*/
+
+class TZ extends Temporal.TimeZone {
+ constructor() { super("UTC") }
+ getOffsetNanosecondsFor() { throw new Test262Error() }
+}
+
+const tz = new TZ();
+const arg = new Temporal.ZonedDateTime(0n, tz);
+const instance = new Temporal.Calendar("iso8601");
+
+assert.throws(Test262Error, () => instance.daysInMonth(arg));
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-slots.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-slots.js
new file mode 100644
index 0000000000..3ca0d6e1d4
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-slots.js
@@ -0,0 +1,40 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: Getters are not called when converting a ZonedDateTime to a PlainDate.
+includes: [compareArray.js]
+features: [Temporal]
+---*/
+
+const actual = [];
+const prototypeDescrs = Object.getOwnPropertyDescriptors(Temporal.ZonedDateTime.prototype);
+const getters = ["year", "month", "monthCode", "day", "hour", "minute", "second", "millisecond", "microsecond", "nanosecond", "calendar"];
+
+for (const property of getters) {
+ Object.defineProperty(Temporal.ZonedDateTime.prototype, property, {
+ get() {
+ actual.push(`get ${property}`);
+ const value = prototypeDescrs[property].get.call(this);
+ return {
+ toString() {
+ actual.push(`toString ${property}`);
+ return value.toString();
+ },
+ valueOf() {
+ actual.push(`valueOf ${property}`);
+ return value;
+ },
+ };
+ },
+ });
+}
+
+const arg = new Temporal.ZonedDateTime(0n, "UTC");
+const instance = new Temporal.Calendar("iso8601");
+instance.daysInMonth(arg);
+assert.compareArray(actual, []);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js
new file mode 100644
index 0000000000..645308ec95
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: RangeError thrown if time zone reports an offset that is not an integer number of nanoseconds
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+[3600_000_000_000.5, NaN, -Infinity, Infinity].forEach((wrongOffset) => {
+ const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset);
+ const calendar = new Temporal.Calendar("iso8601");
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ assert.throws(RangeError, () => calendar.daysInMonth(datetime));
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js
new file mode 100644
index 0000000000..8ed7f33ff2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-not-callable.js
@@ -0,0 +1,23 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: TypeError thrown if timeZone.getOffsetNanosecondsFor is not callable
+features: [BigInt, Symbol, Temporal, arrow-function]
+---*/
+
+[undefined, null, true, Math.PI, 'string', Symbol('sym'), 42n, {}].forEach((notCallable) => {
+ const timeZone = new Temporal.TimeZone("UTC");
+ const calendar = new Temporal.Calendar("iso8601");
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ timeZone.getOffsetNanosecondsFor = notCallable;
+ assert.throws(
+ TypeError,
+ () => calendar.daysInMonth(datetime),
+ `Uncallable ${notCallable === null ? 'null' : typeof notCallable} getOffsetNanosecondsFor should throw TypeError`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js
new file mode 100644
index 0000000000..3ed66442c2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: RangeError thrown if time zone reports an offset that is out of range
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+[-86400_000_000_000, 86400_000_000_000].forEach((wrongOffset) => {
+ const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset);
+ const calendar = new Temporal.Calendar("iso8601");
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ assert.throws(RangeError, () => calendar.daysInMonth(datetime));
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js
new file mode 100644
index 0000000000..5c18bfdbcd
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-wrong-type.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: TypeError thrown if time zone reports an offset that is not a Number
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+[
+ undefined,
+ null,
+ true,
+ "+01:00",
+ Symbol(),
+ 3600_000_000_000n,
+ {},
+ { valueOf() { return 3600_000_000_000; } },
+].forEach((wrongOffset) => {
+ const timeZone = TemporalHelpers.specificOffsetTimeZone(wrongOffset);
+ const calendar = new Temporal.Calendar("iso8601");
+ const datetime = new Temporal.ZonedDateTime(1_000_000_000_987_654_321n, timeZone);
+ assert.throws(TypeError, () => calendar.daysInMonth(datetime));
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/basic.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/basic.js
new file mode 100644
index 0000000000..85985cb146
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/basic.js
@@ -0,0 +1,19 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: Basic tests for daysInMonth().
+features: [Temporal]
+---*/
+
+const iso = Temporal.Calendar.from("iso8601");
+const res = 30;
+assert.sameValue(iso.daysInMonth(Temporal.PlainDate.from("1994-11-05")), res, "PlainDate");
+assert.sameValue(iso.daysInMonth(Temporal.PlainDateTime.from("1994-11-05T08:15:30")), res, "PlainDateTime");
+assert.sameValue(iso.daysInMonth({ year: 1994, month: 11, day: 5 }), res, "property bag");
+assert.sameValue(iso.daysInMonth("1994-11-05"), res, "string");
+assert.throws(TypeError, () => iso.daysInMonth({ year: 2000 }), "property bag with missing properties");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/branding.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/branding.js
new file mode 100644
index 0000000000..0a08a13ba8
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/branding.js
@@ -0,0 +1,27 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: Throw a TypeError if the receiver is invalid
+features: [Symbol, Temporal]
+---*/
+
+const daysInMonth = Temporal.Calendar.prototype.daysInMonth;
+
+assert.sameValue(typeof daysInMonth, "function");
+
+const args = [new Temporal.PlainDate(2000, 1, 1)];
+
+assert.throws(TypeError, () => daysInMonth.apply(undefined, args), "undefined");
+assert.throws(TypeError, () => daysInMonth.apply(null, args), "null");
+assert.throws(TypeError, () => daysInMonth.apply(true, args), "true");
+assert.throws(TypeError, () => daysInMonth.apply("", args), "empty string");
+assert.throws(TypeError, () => daysInMonth.apply(Symbol(), args), "symbol");
+assert.throws(TypeError, () => daysInMonth.apply(1, args), "1");
+assert.throws(TypeError, () => daysInMonth.apply({}, args), "plain object");
+assert.throws(TypeError, () => daysInMonth.apply(Temporal.Calendar, args), "Temporal.Calendar");
+assert.throws(TypeError, () => daysInMonth.apply(Temporal.Calendar.prototype, args), "Temporal.Calendar.prototype");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/browser.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/browser.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/browser.js
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/builtin.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/builtin.js
new file mode 100644
index 0000000000..55e16b81a4
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/builtin.js
@@ -0,0 +1,36 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: >
+ Tests that Temporal.Calendar.prototype.daysInMonth
+ meets the requirements for built-in objects defined by the
+ introduction of chapter 17 of the ECMAScript Language Specification.
+info: |
+ Built-in functions that are not constructors do not have a "prototype" property unless
+ otherwise specified in the description of a particular function.
+
+ Unless specified otherwise, a built-in object that is callable as a function is a built-in
+ function object with the characteristics described in 10.3. Unless specified otherwise, the
+ [[Extensible]] internal slot of a built-in object initially has the value true.
+
+ Unless otherwise specified every built-in function and every built-in constructor has the
+ Function prototype object [...] as the value of its [[Prototype]] internal slot.
+features: [Temporal]
+---*/
+
+assert.sameValue(Object.isExtensible(Temporal.Calendar.prototype.daysInMonth),
+ true, "Built-in objects must be extensible.");
+
+assert.sameValue(Object.prototype.toString.call(Temporal.Calendar.prototype.daysInMonth),
+ "[object Function]", "Object.prototype.toString");
+
+assert.sameValue(Object.getPrototypeOf(Temporal.Calendar.prototype.daysInMonth),
+ Function.prototype, "prototype");
+
+assert.sameValue(Temporal.Calendar.prototype.daysInMonth.hasOwnProperty("prototype"),
+ false, "prototype property");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/calendar-datefromfields-called-with-options-undefined.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/calendar-datefromfields-called-with-options-undefined.js
new file mode 100644
index 0000000000..30931996c1
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/calendar-datefromfields-called-with-options-undefined.js
@@ -0,0 +1,18 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: >
+ Calendar.dateFromFields method is called with undefined as the options value
+ when call originates internally
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const calendar = TemporalHelpers.calendarFromFieldsUndefinedOptions();
+calendar.daysInMonth({ year: 2000, month: 5, day: 3, calendar });
+assert.sameValue(calendar.dateFromFieldsCallCount, 1);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/calendar-fields-iterable.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/calendar-fields-iterable.js
new file mode 100644
index 0000000000..9ea5126443
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/calendar-fields-iterable.js
@@ -0,0 +1,35 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: Verify the result of calendar.fields() is treated correctly.
+info: |
+ sec-temporal.calendar.prototype.daysinmonth step 4.a:
+ a. Set _dateOrDateTime_ to ? ToTemporalDate(_dateOrDateTime_).
+ sec-temporal-totemporaldate step 2.c:
+ c. Let _fieldNames_ be ? CalendarFields(_calendar_, « *"day"*, *"month"*, *"monthCode"*, *"year"* »).
+ sec-temporal-calendarfields step 4:
+ 4. Let _result_ be ? IterableToListOfType(_fieldsArray_, « String »).
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const expected = [
+ "day",
+ "month",
+ "monthCode",
+ "year",
+];
+
+const calendar1 = TemporalHelpers.calendarFieldsIterable();
+const calendar2 = TemporalHelpers.calendarFieldsIterable();
+calendar1.daysInMonth({ year: 2000, month: 5, day: 2, calendar: calendar2 });
+
+assert.sameValue(calendar1.fieldsCallCount, 0, "fields() method not called");
+assert.sameValue(calendar2.fieldsCallCount, 1, "fields() method called once");
+assert.compareArray(calendar2.fieldsCalledWith[0], expected, "fields() method called with correct args");
+assert(calendar2.iteratorExhausted[0], "iterated through the whole iterable");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/calendar-temporal-object.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/calendar-temporal-object.js
new file mode 100644
index 0000000000..00bad9889f
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/calendar-temporal-object.js
@@ -0,0 +1,29 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: Fast path for converting other Temporal objects to Temporal.Calendar by reading internal slots
+info: |
+ sec-temporal.calendar.prototype.daysinmonth step 4.a:
+ a. Set _dateOrDateTime_ to ? ToTemporalDate(_dateOrDateTime_).
+ sec-temporal-totemporaldate step 2.c:
+ c. Let _calendar_ be ? GetTemporalCalendarWithISODefault(_item_).
+ sec-temporal-gettemporalcalendarwithisodefault step 2:
+ 2. Return ? ToTemporalCalendarWithISODefault(_calendar_).
+ sec-temporal-totemporalcalendarwithisodefault step 2:
+ 3. Return ? ToTemporalCalendar(_temporalCalendarLike_).
+ sec-temporal-totemporalcalendar step 1.a:
+ a. If _temporalCalendarLike_ has an [[InitializedTemporalDate]], [[InitializedTemporalDateTime]], [[InitializedTemporalMonthDay]], [[InitializedTemporalYearMonth]], or [[InitializedTemporalZonedDateTime]] internal slot, then
+ i. Return _temporalCalendarLike_.[[Calendar]].
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+TemporalHelpers.checkToTemporalCalendarFastPath((temporalObject) => {
+ const calendar = new Temporal.Calendar("iso8601");
+ calendar.daysInMonth({ year: 2000, month: 5, day: 2, calendar: temporalObject });
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/infinity-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/infinity-throws-rangeerror.js
new file mode 100644
index 0000000000..eb47f7d645
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/infinity-throws-rangeerror.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: Throws if any value in the property bag is Infinity or -Infinity
+esid: sec-temporal.calendar.prototype.daysinmonth
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const instance = new Temporal.Calendar("iso8601");
+const base = { year: 2000, month: 5, day: 2 };
+
+[Infinity, -Infinity].forEach((inf) => {
+ ["year", "month", "day"].forEach((prop) => {
+ assert.throws(RangeError, () => instance.daysInMonth({ ...base, [prop]: inf }), `${prop} property cannot be ${inf}`);
+
+ const calls = [];
+ const obj = TemporalHelpers.toPrimitiveObserver(calls, inf, prop);
+ assert.throws(RangeError, () => instance.daysInMonth({ ...base, [prop]: obj }));
+ assert.compareArray(calls, [`get ${prop}.valueOf`, `call ${prop}.valueOf`], "it fails after fetching the primitive value");
+ });
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/length.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/length.js
new file mode 100644
index 0000000000..fe4acc1334
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/length.js
@@ -0,0 +1,28 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2020 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: Temporal.Calendar.prototype.daysInMonth.length is 1
+info: |
+ Every built-in function object, including constructors, has a "length" property whose value is
+ an integer. Unless otherwise specified, this value is equal to the largest number of named
+ arguments shown in the subclause headings for the function description. Optional parameters
+ (which are indicated with brackets: [ ]) or rest parameters (which are shown using the form
+ «...name») are not included in the default argument count.
+
+ Unless otherwise specified, the "length" property of a built-in function object has the
+ attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+verifyProperty(Temporal.Calendar.prototype.daysInMonth, "length", {
+ value: 1,
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/name.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/name.js
new file mode 100644
index 0000000000..6d65a4c15a
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/name.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: Temporal.Calendar.prototype.daysInMonth.name is "daysInMonth".
+info: |
+ Every built-in function object, including constructors, that is not identified as an anonymous
+ function has a "name" property whose value is a String. Unless otherwise specified, this value
+ is the name that is given to the function in this specification.
+
+ Unless otherwise specified, the "name" property of a built-in function object, if it exists,
+ has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+verifyProperty(Temporal.Calendar.prototype.daysInMonth, "name", {
+ value: "daysInMonth",
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/not-a-constructor.js
new file mode 100644
index 0000000000..f7edc90848
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/not-a-constructor.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: >
+ Temporal.Calendar.prototype.daysInMonth does not implement [[Construct]], is not new-able
+info: |
+ Built-in function objects that are not identified as constructors do not implement the
+ [[Construct]] internal method unless otherwise specified in the description of a particular
+ function.
+includes: [isConstructor.js]
+features: [Reflect.construct, Temporal]
+---*/
+
+assert.throws(TypeError, () => {
+ new Temporal.Calendar.prototype.daysInMonth();
+}, "Calling as constructor");
+
+assert.sameValue(isConstructor(Temporal.Calendar.prototype.daysInMonth), false,
+ "isConstructor(Temporal.Calendar.prototype.daysInMonth)");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/plain-date-time.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/plain-date-time.js
new file mode 100644
index 0000000000..26e9a810fd
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/plain-date-time.js
@@ -0,0 +1,116 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: >
+ Temporal.Calendar.prototype.daysInMonth will take Temporal.PlainDateTime object
+ and return the number of days in that month.
+info: |
+ 4. If Type(temporalDateLike) is not Object or temporalDateLike does not have an [[InitializedTemporalDate]] or [[InitializedTemporalYearMonth]] internal slots, then
+ a. Set temporalDateLike to ? ToTemporalDate(temporalDateLike).
+ 5. Return 𝔽(! ISODaysInMonth(temporalDateLike.[[ISOYear]], temporalDateLike.[[ISOMonth]])).
+features: [Temporal]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+let dt = new Temporal.PlainDateTime(1997, 1, 23, 5, 30, 13);
+assert.sameValue(
+ cal.daysInMonth(dt),
+ 31,
+ 'cal.daysInMonth(new Temporal.PlainDateTime(1997, 1, 23, 5, 30, 13)) must return 31'
+);
+
+// leap year
+dt = new Temporal.PlainDateTime(1996, 2, 23, 5, 30, 13);
+assert.sameValue(
+ cal.daysInMonth(dt),
+ 29,
+ 'cal.daysInMonth(new Temporal.PlainDateTime(1996, 2, 23, 5, 30, 13)) must return 29'
+);
+dt = new Temporal.PlainDateTime(2000, 2, 23, 5, 30, 13);
+assert.sameValue(
+ cal.daysInMonth(dt),
+ 29,
+ 'cal.daysInMonth(new Temporal.PlainDateTime(2000, 2, 23, 5, 30, 13)) must return 29'
+);
+
+// non leap year
+dt = new Temporal.PlainDateTime(1997, 2, 23, 5, 30, 13);
+assert.sameValue(
+ cal.daysInMonth(dt),
+ 28,
+ 'cal.daysInMonth(new Temporal.PlainDateTime(1997, 2, 23, 5, 30, 13)) must return 28'
+);
+
+dt = new Temporal.PlainDateTime(1997, 3, 23, 5, 30, 13);
+assert.sameValue(
+ cal.daysInMonth(dt),
+ 31,
+ 'cal.daysInMonth(new Temporal.PlainDateTime(1997, 3, 23, 5, 30, 13)) must return 31'
+);
+
+dt = new Temporal.PlainDateTime(1997, 4, 23, 5, 30, 13);
+assert.sameValue(
+ cal.daysInMonth(dt),
+ 30,
+ 'cal.daysInMonth(new Temporal.PlainDateTime(1997, 4, 23, 5, 30, 13)) must return 30'
+);
+
+dt = new Temporal.PlainDateTime(1997, 5, 23, 5, 30, 13);
+assert.sameValue(
+ cal.daysInMonth(dt),
+ 31,
+ 'cal.daysInMonth(new Temporal.PlainDateTime(1997, 5, 23, 5, 30, 13)) must return 31'
+);
+
+dt = new Temporal.PlainDateTime(1997, 6, 23, 5, 30, 13);
+assert.sameValue(
+ cal.daysInMonth(dt),
+ 30,
+ 'cal.daysInMonth(new Temporal.PlainDateTime(1997, 6, 23, 5, 30, 13)) must return 30'
+);
+
+dt = new Temporal.PlainDateTime(1997, 7, 23, 5, 30, 13);
+assert.sameValue(
+ cal.daysInMonth(dt),
+ 31,
+ 'cal.daysInMonth(new Temporal.PlainDateTime(1997, 7, 23, 5, 30, 13)) must return 31'
+);
+
+dt = new Temporal.PlainDateTime(1997, 8, 23, 5, 30, 13);
+assert.sameValue(
+ cal.daysInMonth(dt),
+ 31,
+ 'cal.daysInMonth(new Temporal.PlainDateTime(1997, 8, 23, 5, 30, 13)) must return 31'
+);
+
+dt = new Temporal.PlainDateTime(1997, 9, 23, 5, 30, 13);
+assert.sameValue(
+ cal.daysInMonth(dt),
+ 30,
+ 'cal.daysInMonth(new Temporal.PlainDateTime(1997, 9, 23, 5, 30, 13)) must return 30'
+);
+
+dt = new Temporal.PlainDateTime(1997, 10, 23, 5, 30, 13);
+assert.sameValue(
+ cal.daysInMonth(dt),
+ 31,
+ 'cal.daysInMonth(new Temporal.PlainDateTime(1997, 10, 23, 5, 30, 13)) must return 31'
+);
+
+dt = new Temporal.PlainDateTime(1997, 11, 23, 5, 30, 13);
+assert.sameValue(
+ cal.daysInMonth(dt),
+ 30,
+ 'cal.daysInMonth(new Temporal.PlainDateTime(1997, 11, 23, 5, 30, 13)) must return 30'
+);
+
+dt = new Temporal.PlainDateTime(1997, 12, 23, 5, 30, 13);
+assert.sameValue(
+ cal.daysInMonth(dt),
+ 31,
+ 'cal.daysInMonth(new Temporal.PlainDateTime(1997, 12, 23, 5, 30, 13)) must return 31'
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/plain-date.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/plain-date.js
new file mode 100644
index 0000000000..edb6f55093
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/plain-date.js
@@ -0,0 +1,58 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: >
+ Temporal.Calendar.prototype.daysInMonth will take Temporal.PlainDate object
+ and return the number of days in that month.
+info: |
+ 5. Return 𝔽(! ISODaysInMonth(temporalDateLike.[[ISOYear]], temporalDateLike.[[ISOMonth]])).
+features: [Temporal]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+let d = new Temporal.PlainDate(2021, 1, 15);
+assert.sameValue(cal.daysInMonth(d), 31, 'cal.daysInMonth(new Temporal.PlainDate(2021, 1, 15)) must return 31');
+
+// non-leap year
+d = new Temporal.PlainDate(2021, 2, 15);
+assert.sameValue(cal.daysInMonth(d), 28, 'cal.daysInMonth(new Temporal.PlainDate(2021, 2, 15)) must return 28');
+
+// leap year
+d = new Temporal.PlainDate(2020, 2, 15);
+assert.sameValue(cal.daysInMonth(d), 29, 'cal.daysInMonth(new Temporal.PlainDate(2020, 2, 15)) must return 29');
+d = new Temporal.PlainDate(2000, 2, 15);
+assert.sameValue(cal.daysInMonth(d), 29, 'cal.daysInMonth(new Temporal.PlainDate(2000, 2, 15)) must return 29');
+
+d = new Temporal.PlainDate(2021, 3, 15);
+assert.sameValue(cal.daysInMonth(d), 31, 'cal.daysInMonth(new Temporal.PlainDate(2021, 3, 15)) must return 31');
+
+d = new Temporal.PlainDate(2021, 4, 15);
+assert.sameValue(cal.daysInMonth(d), 30, 'cal.daysInMonth(new Temporal.PlainDate(2021, 4, 15)) must return 30');
+
+d = new Temporal.PlainDate(2021, 5, 15);
+assert.sameValue(cal.daysInMonth(d), 31, 'cal.daysInMonth(new Temporal.PlainDate(2021, 5, 15)) must return 31');
+
+d = new Temporal.PlainDate(2021, 6, 15);
+assert.sameValue(cal.daysInMonth(d), 30, 'cal.daysInMonth(new Temporal.PlainDate(2021, 6, 15)) must return 30');
+
+d = new Temporal.PlainDate(2021, 7, 15);
+assert.sameValue(cal.daysInMonth(d), 31, 'cal.daysInMonth(new Temporal.PlainDate(2021, 7, 15)) must return 31');
+
+d = new Temporal.PlainDate(2021, 8, 15);
+assert.sameValue(cal.daysInMonth(d), 31, 'cal.daysInMonth(new Temporal.PlainDate(2021, 8, 15)) must return 31');
+
+d = new Temporal.PlainDate(2021, 9, 15);
+assert.sameValue(cal.daysInMonth(d), 30, 'cal.daysInMonth(new Temporal.PlainDate(2021, 9, 15)) must return 30');
+
+d = new Temporal.PlainDate(2021, 10, 15);
+assert.sameValue(cal.daysInMonth(d), 31, 'cal.daysInMonth(new Temporal.PlainDate(2021, 10, 15)) must return 31');
+
+d = new Temporal.PlainDate(2021, 11, 15);
+assert.sameValue(cal.daysInMonth(d), 30, 'cal.daysInMonth(new Temporal.PlainDate(2021, 11, 15)) must return 30');
+
+d = new Temporal.PlainDate(2021, 12, 15);
+assert.sameValue(cal.daysInMonth(d), 31, 'cal.daysInMonth(new Temporal.PlainDate(2021, 12, 15)) must return 31');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/prop-desc.js
new file mode 100644
index 0000000000..d2f45ed5ca
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/prop-desc.js
@@ -0,0 +1,24 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: The "daysInMonth" property of Temporal.Calendar.prototype
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+assert.sameValue(
+ typeof Temporal.Calendar.prototype.daysInMonth,
+ "function",
+ "`typeof Calendar.prototype.daysInMonth` is `function`"
+);
+
+verifyProperty(Temporal.Calendar.prototype, "daysInMonth", {
+ writable: true,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/shell.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/shell.js
new file mode 100644
index 0000000000..eda1477282
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/shell.js
@@ -0,0 +1,24 @@
+// GENERATED, DO NOT EDIT
+// file: isConstructor.js
+// Copyright (C) 2017 André Bargull. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+description: |
+ Test if a given function is a constructor function.
+defines: [isConstructor]
+features: [Reflect.construct]
+---*/
+
+function isConstructor(f) {
+ if (typeof f !== "function") {
+ throw new Test262Error("isConstructor invoked with a non-function value");
+ }
+
+ try {
+ Reflect.construct(function(){}, [], f);
+ } catch (e) {
+ return false;
+ }
+ return true;
+}
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/string.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/string.js
new file mode 100644
index 0000000000..0f236a1622
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/string.js
@@ -0,0 +1,35 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: >
+ Temporal.Calendar.prototype.daysInMonth will take ISO8601 string
+ and return the number of days in that month.
+info: |
+ 4. If Type(temporalDateLike) is not Object or temporalDateLike does not have
+ an [[InitializedTemporalDate]] or [[InitializedTemporalYearMonth]] internal
+ slots, then
+ a. Set temporalDateLike to ? ToTemporalDate(temporalDateLike).
+ 5. Return 𝔽(! ISODaysInMonth(temporalDateLike.[[ISOYear]], temporalDateLike.[[ISOMonth]])).
+features: [Temporal]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+assert.sameValue(cal.daysInMonth("2019-01-18"), 31, 'cal.daysInMonth("2019-01-18") must return 31');
+// leap year
+assert.sameValue(cal.daysInMonth("2020-02-18"), 29, 'cal.daysInMonth("2020-02-18") must return 29');
+// non leap
+assert.sameValue(cal.daysInMonth("2019-02-18"), 28, 'cal.daysInMonth("2019-02-18") must return 28');
+assert.sameValue(cal.daysInMonth("2019-03-18"), 31, 'cal.daysInMonth("2019-03-18") must return 31');
+assert.sameValue(cal.daysInMonth("2019-04-18"), 30, 'cal.daysInMonth("2019-04-18") must return 30');
+assert.sameValue(cal.daysInMonth("2019-05-18"), 31, 'cal.daysInMonth("2019-05-18") must return 31');
+assert.sameValue(cal.daysInMonth("2019-06-18"), 30, 'cal.daysInMonth("2019-06-18") must return 30');
+assert.sameValue(cal.daysInMonth("2019-07-18"), 31, 'cal.daysInMonth("2019-07-18") must return 31');
+assert.sameValue(cal.daysInMonth("2019-08-18"), 31, 'cal.daysInMonth("2019-08-18") must return 31');
+assert.sameValue(cal.daysInMonth("2019-09-18"), 30, 'cal.daysInMonth("2019-09-18") must return 30');
+assert.sameValue(cal.daysInMonth("2019-10-18"), 31, 'cal.daysInMonth("2019-10-18") must return 31');
+assert.sameValue(cal.daysInMonth("2019-11-18"), 30, 'cal.daysInMonth("2019-11-18") must return 30');
+assert.sameValue(cal.daysInMonth("2019-12-18"), 31, 'cal.daysInMonth("2019-12-18") must return 31');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/throw-range-error-ToTemporalDate.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/throw-range-error-ToTemporalDate.js
new file mode 100644
index 0000000000..6571d37f2d
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/throw-range-error-ToTemporalDate.js
@@ -0,0 +1,21 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2021 the V8 project authors. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-temporal.calendar.prototype.daysInMonth
+description: >
+ Temporal.Calendar.prototype.daysInMonth throws RangeError on
+ ToTemporalDate when temporalDateLike is invalid string.
+info: |
+ 4. If Type(temporalDateLike) is not Object or temporalDateLike does not have
+ an [[InitializedTemporalDate]] or [[InitializedTemporalYearMonth]] internal
+ slots, then
+ a. Set temporalDateLike to ? ToTemporalDate(temporalDateLike).
+features: [Temporal, arrow-function]
+---*/
+let cal = new Temporal.Calendar("iso8601");
+
+assert.throws(RangeError, () => cal.daysInMonth("invalid string"),
+ 'cal.daysInMonth("invalid string") throws a RangeError exception');
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/year-zero.js b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/year-zero.js
new file mode 100644
index 0000000000..7974098376
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/Calendar/prototype/daysInMonth/year-zero.js
@@ -0,0 +1,26 @@
+// |reftest| skip-if(!this.hasOwnProperty('Temporal')) -- Temporal is not enabled unconditionally
+// Copyright (C) 2022 Igalia, S.L. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-temporal.calendar.prototype.daysinmonth
+description: Negative zero, as an extended year, is rejected
+features: [Temporal, arrow-function]
+---*/
+
+const invalidStrings = [
+ "-000000-10-31",
+ "-000000-10-31T00:45",
+ "-000000-10-31T00:45+01:00",
+ "-000000-10-31T00:45+00:00[UTC]",
+];
+const instance = new Temporal.Calendar("iso8601");
+invalidStrings.forEach((arg) => {
+ assert.throws(
+ RangeError,
+ () => instance.daysInMonth(arg),
+ "reject minus zero as extended year"
+ );
+});
+
+reportCompare(0, 0);