summaryrefslogtreecommitdiffstats
path: root/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract')
-rw-r--r--js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/ambiguous-date.js32
-rw-r--r--js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/argument-duration-max.js58
-rw-r--r--js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/argument-duration-out-of-range.js75
-rw-r--r--js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/argument-duration.js21
-rw-r--r--js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/argument-invalid-property.js31
-rw-r--r--js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/argument-mixed-sign.js21
-rw-r--r--js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/argument-not-object.js22
-rw-r--r--js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/argument-singular-properties.js30
-rw-r--r--js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/argument-string-fractional-units-rounding-mode.js19
-rw-r--r--js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/argument-string-negative-fractional-units.js20
-rw-r--r--js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/argument-string.js16
-rw-r--r--js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/balance-negative-time-units.js52
-rw-r--r--js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/branding.js27
-rw-r--r--js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/browser.js0
-rw-r--r--js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/builtin-calendar-no-observable-calls.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/builtin.js36
-rw-r--r--js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/calendar-dateadd.js32
-rw-r--r--js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/hour-overflow.js33
-rw-r--r--js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/infinity-throws-rangeerror.js38
-rw-r--r--js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/length.js28
-rw-r--r--js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/limits.js27
-rw-r--r--js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/name.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/negative-duration.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/negative-infinity-throws-rangeerror.js38
-rw-r--r--js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/non-integer-throws-rangeerror.js29
-rw-r--r--js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/not-a-constructor.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/options-empty.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/options-invalid.js23
-rw-r--r--js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/options-undefined.js22
-rw-r--r--js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/options-wrong-type.js26
-rw-r--r--js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/order-of-operations.js127
-rw-r--r--js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/overflow-invalid-string.js33
-rw-r--r--js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/overflow-undefined.js31
-rw-r--r--js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/overflow-wrong-type.js30
-rw-r--r--js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/prop-desc.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/shell.js24
-rw-r--r--js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/subclassing-ignored.js20
37 files changed, 1175 insertions, 0 deletions
diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/ambiguous-date.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/ambiguous-date.js
new file mode 100644
index 0000000000..f23e3f376c
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/ambiguous-date.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.plaindatetime.prototype.subtract
+description: Ambiguous subtraction is handled according to the overflow option
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+const mar31 = new Temporal.PlainDateTime(2020, 3, 31, 15, 0);
+
+TemporalHelpers.assertPlainDateTime(
+ mar31.subtract({ months: 1 }),
+ 2020, 2, "M02", 29, 15, 0, 0, 0, 0, 0,
+ "constrain when ambiguous result (overflow options not supplied)"
+);
+
+TemporalHelpers.assertPlainDateTime(
+ mar31.subtract({ months: 1 }, { overflow: "constrain" }),
+ 2020, 2, "M02", 29, 15, 0, 0, 0, 0, 0,
+ "constrain when ambiguous result (overflow options supplied)"
+);
+
+assert.throws(
+ RangeError,
+ () => mar31.subtract({ months: 1 }, { overflow: "reject" }),
+ "throw when ambiguous result with reject"
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/argument-duration-max.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/argument-duration-max.js
new file mode 100644
index 0000000000..7b43031195
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/argument-duration-max.js
@@ -0,0 +1,58 @@
+// |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.plaindatetime.prototype.subtract
+description: Maximum allowed duration
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const instance = new Temporal.PlainDateTime(1970, 1, 1);
+
+const maxCases = [
+ ["P273790Y8M11DT23H59M59.999999999S", "string with max years"],
+ [{ years: 273790, months: 8, days: 11, nanoseconds: 86399999999999 }, "property bag with max years"],
+ ["P3285488M11DT23H59M59.999999999S", "string with max months"],
+ [{ months: 3285488, days: 11, nanoseconds: 86399999999999 }, "property bag with max months"],
+ ["P14285714W2DT23H59M59.999999999S", "string with max weeks"],
+ [{ weeks: 14285714, days: 2, nanoseconds: 86399999999999 }, "property bag with max weeks"],
+ ["P100000000DT23H59M59.999999999S", "string with max days"],
+ [{ days: 100000000, nanoseconds: 86399999999999 }, "property bag with max days"],
+ ["PT2400000023H59M59.999999999S", "string with max hours"],
+ [{ hours: 2400000023, nanoseconds: 3599999999999 }, "property bag with max hours"],
+ ["PT144000001439M59.999999999S", "string with max minutes"],
+ [{ minutes: 144000001439, nanoseconds: 59999999999 }, "property bag with max minutes"],
+ ["PT8640000086399.999999999S", "string with max seconds"],
+ [{ seconds: 8640000086399, nanoseconds: 999999999 }, "property bag with max seconds"],
+];
+
+for (const [arg, descr] of maxCases) {
+ const result = instance.subtract(arg);
+ TemporalHelpers.assertPlainDateTime(result, -271821, 4, "M04", 19, 0, 0, 0, 0, 0, 1, `operation succeeds with ${descr}`);
+}
+
+const minCases = [
+ ["-P273790Y8M12DT23H59M59.999999999S", "string with min years"],
+ [{ years: -273790, months: -8, days: -12, nanoseconds: -86399999999999 }, "property bag with min years"],
+ ["-P3285488M12DT23H59M59.999999999S", "string with min months"],
+ [{ months: -3285488, days: -12, nanoseconds: -86399999999999 }, "property bag with min months"],
+ ["-P14285714W2DT23H59M59.999999999S", "string with min weeks"],
+ [{ weeks: -14285714, days: -2, nanoseconds: -86399999999999 }, "property bag with min weeks"],
+ ["-P100000000DT23H59M59.999999999S", "string with min days"],
+ [{ days: -100000000, nanoseconds: -86399999999999 }, "property bag with min days"],
+ ["-PT2400000023H59M59.999999999S", "string with min hours"],
+ [{ hours: -2400000023, nanoseconds: -3599999999999 }, "property bag with min hours"],
+ ["-PT144000001439M59.999999999S", "string with min minutes"],
+ [{ minutes: -144000001439, nanoseconds: -59999999999 }, "property bag with min minutes"],
+ ["-PT8640000086399.999999999S", "string with min seconds"],
+ [{ seconds: -8640000086399, nanoseconds: -999999999 }, "property bag with min seconds"],
+];
+
+for (const [arg, descr] of minCases) {
+ const result = instance.subtract(arg);
+ TemporalHelpers.assertPlainDateTime(result, 275760, 9, "M09", 13, 23, 59, 59, 999, 999, 999, `operation succeeds with ${descr}`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/argument-duration-out-of-range.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/argument-duration-out-of-range.js
new file mode 100644
index 0000000000..d5067d41f8
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/argument-duration-out-of-range.js
@@ -0,0 +1,75 @@
+// |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.plaindatetime.prototype.subtract
+description: Duration-like argument that is out of range
+features: [Temporal]
+---*/
+
+const instance = new Temporal.PlainDateTime(1970, 1, 1);
+
+const cases = [
+ // 2^32 = 4294967296
+ ["P4294967296Y", "string with years > max"],
+ [{ years: 4294967296 }, "property bag with years > max"],
+ ["-P4294967296Y", "string with years < min"],
+ [{ years: -4294967296 }, "property bag with years < min"],
+ ["P4294967296M", "string with months > max"],
+ [{ months: 4294967296 }, "property bag with months > max"],
+ ["-P4294967296M", "string with months < min"],
+ [{ months: -4294967296 }, "property bag with months < min"],
+ ["P4294967296W", "string with weeks > max"],
+ [{ weeks: 4294967296 }, "property bag with weeks > max"],
+ ["-P4294967296W", "string with weeks < min"],
+ [{ weeks: -4294967296 }, "property bag with weeks < min"],
+
+ // ceil(max safe integer / 86400) = 104249991375
+ ["P104249991375D", "string with days > max"],
+ [{ days: 104249991375 }, "property bag with days > max"],
+ ["P104249991374DT24H", "string where hours balance into days > max"],
+ [{ days: 104249991374, hours: 24 }, "property bag where hours balance into days > max"],
+ ["-P104249991375D", "string with days < min"],
+ [{ days: -104249991375 }, "property bag with days < min"],
+ ["-P104249991374DT24H", "string where hours balance into days < min"],
+ [{ days: -104249991374, hours: -24 }, "property bag where hours balance into days < min"],
+
+ // ceil(max safe integer / 3600) = 2501999792984
+ ["PT2501999792984H", "string with hours > max"],
+ [{ hours: 2501999792984 }, "property bag with hours > max"],
+ ["PT2501999792983H60M", "string where minutes balance into hours > max"],
+ [{ hours: 2501999792983, minutes: 60 }, "property bag where minutes balance into hours > max"],
+ ["-PT2501999792984H", "string with hours < min"],
+ [{ hours: -2501999792984 }, "property bag with hours < min"],
+ ["-PT2501999792983H60M", "string where minutes balance into hours < min"],
+ [{ hours: -2501999792983, minutes: -60 }, "property bag where minutes balance into hours < min"],
+
+ // ceil(max safe integer / 60) = 150119987579017
+ ["PT150119987579017M", "string with minutes > max"],
+ [{ minutes: 150119987579017 }, "property bag with minutes > max"],
+ ["PT150119987579016M60S", "string where seconds balance into minutes > max"],
+ [{ minutes: 150119987579016, seconds: 60 }, "property bag where seconds balance into minutes > max"],
+ ["-PT150119987579017M", "string with minutes < min"],
+ [{ minutes: -150119987579017 }, "property bag with minutes < min"],
+ ["-PT150119987579016M60S", "string where seconds balance into minutes < min"],
+ [{ minutes: -150119987579016, seconds: -60 }, "property bag where seconds balance into minutes < min"],
+
+ // 2^53 = 9007199254740992
+ ["PT9007199254740992S", "string with seconds > max"],
+ [{ seconds: 9007199254740992 }, "property bag with seconds > max"],
+ [{ seconds: 9007199254740991, milliseconds: 1000 }, "property bag where milliseconds balance into seconds > max"],
+ [{ seconds: 9007199254740991, microseconds: 1000000 }, "property bag where microseconds balance into seconds > max"],
+ [{ seconds: 9007199254740991, nanoseconds: 1000000000 }, "property bag where nanoseconds balance into seconds > max"],
+ ["-PT9007199254740992S", "string with seconds < min"],
+ [{ seconds: -9007199254740992 }, "property bag with seconds < min"],
+ [{ seconds: -9007199254740991, milliseconds: -1000 }, "property bag where milliseconds balance into seconds < min"],
+ [{ seconds: -9007199254740991, microseconds: -1000000 }, "property bag where microseconds balance into seconds < min"],
+ [{ seconds: -9007199254740991, nanoseconds: -1000000000 }, "property bag where nanoseconds balance into seconds < min"],
+];
+
+for (const [arg, descr] of cases) {
+ assert.throws(RangeError, () => instance.subtract(arg), `${descr} is out of range`);
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/argument-duration.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/argument-duration.js
new file mode 100644
index 0000000000..bc8df78a45
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/argument-duration.js
@@ -0,0 +1,21 @@
+// |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.plaindatetime.prototype.subtract
+description: Duration object arguments are handled
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+const jan31 = new Temporal.PlainDateTime(2020, 1, 31, 15, 0);
+
+const subtractWithDuration = jan31.subtract(new Temporal.Duration(0, 1, 0, 0, 0, 1));
+TemporalHelpers.assertPlainDateTime(
+ subtractWithDuration,
+ 2019, 12, "M12", 31, 14, 59, 0, 0, 0, 0,
+ "Duration argument"
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/argument-invalid-property.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/argument-invalid-property.js
new file mode 100644
index 0000000000..139dfa66ea
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/argument-invalid-property.js
@@ -0,0 +1,31 @@
+// |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.plaindatetime.prototype.subtract
+description: temporalDurationLike object must contain at least one correctly spelled property
+features: [Temporal]
+---*/
+
+const instance = new Temporal.PlainDateTime(2000, 5, 2, 15, 30, 45, 987, 654, 321);
+
+assert.throws(
+ TypeError,
+ () => instance.subtract({}),
+ "Throws TypeError if no property is present"
+);
+
+assert.throws(
+ TypeError,
+ () => instance.subtract({ nonsense: true }),
+ "Throws TypeError if no recognized property is present"
+);
+
+assert.throws(
+ TypeError,
+ () => instance.subtract({ sign: 1 }),
+ "Sign property is not recognized"
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/argument-mixed-sign.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/argument-mixed-sign.js
new file mode 100644
index 0000000000..82e4584910
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/argument-mixed-sign.js
@@ -0,0 +1,21 @@
+// |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.plaindatetime.prototype.subtract
+description: Positive and negative values in the temporalDurationLike argument are not acceptable
+features: [Temporal]
+---*/
+
+const instance = new Temporal.PlainDateTime(2000, 5, 2, 15, 30, 45, 987, 654, 321);
+
+["constrain", "reject"].forEach((overflow) => {
+ assert.throws(
+ RangeError,
+ () => instance.subtract({ hours: 1, minutes: -30 }, { overflow }),
+ `mixed positive and negative values always throw (overflow = "${overflow}")`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/argument-not-object.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/argument-not-object.js
new file mode 100644
index 0000000000..62a65a3720
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/argument-not-object.js
@@ -0,0 +1,22 @@
+// |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.plaindatetime.prototype.subtract
+description: Passing a primitive other than string to subtract() throws
+features: [Symbol, Temporal]
+---*/
+
+const instance = new Temporal.PlainDateTime(2000, 5, 2, 15, 30, 45, 987, 654, 321);
+assert.throws(TypeError, () => instance.subtract(undefined), "undefined");
+assert.throws(TypeError, () => instance.subtract(null), "null");
+assert.throws(TypeError, () => instance.subtract(true), "boolean");
+assert.throws(RangeError, () => instance.subtract(""), "empty string");
+assert.throws(TypeError, () => instance.subtract(Symbol()), "Symbol");
+assert.throws(TypeError, () => instance.subtract(7), "number");
+assert.throws(TypeError, () => instance.subtract(7n), "bigint");
+assert.throws(TypeError, () => instance.subtract([]), "array");
+assert.throws(TypeError, () => instance.subtract(() => {}), "function");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/argument-singular-properties.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/argument-singular-properties.js
new file mode 100644
index 0000000000..c033a487eb
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/argument-singular-properties.js
@@ -0,0 +1,30 @@
+// |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.plaindatetime.prototype.subtract
+description: Singular properties in the property bag are always ignored
+features: [Temporal]
+---*/
+
+const instance = new Temporal.PlainDateTime(2000, 5, 2, 15, 30, 45, 987, 654, 321);
+
+[
+ { year: 1 },
+ { month: 2 },
+ { week: 3 },
+ { day: 4 },
+ { hour: 5 },
+ { minute: 6 },
+ { second: 7 },
+ { millisecond: 8 },
+ { microsecond: 9 },
+ { nanosecond: 10 },
+].forEach((badObject) => {
+ assert.throws(TypeError, () => instance.subtract(badObject),
+ "Throw TypeError if temporalDurationLike is not valid");
+});
+
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/argument-string-fractional-units-rounding-mode.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/argument-string-fractional-units-rounding-mode.js
new file mode 100644
index 0000000000..ff4eb22bd4
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/argument-string-fractional-units-rounding-mode.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.plaindatetime.prototype.subtract
+description: Strings with fractional duration units are rounded with the correct rounding mode
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const datetime = new Temporal.PlainDateTime(2000, 5, 2);
+
+TemporalHelpers.assertPlainDateTime(datetime.subtract("PT1.03125H"), 2000, 5, "M05", 1, 22, 58, 7, 500, 0, 0,
+ "positive fractional units rounded with correct rounding mode");
+TemporalHelpers.assertPlainDateTime(datetime.subtract("-PT1.03125H"), 2000, 5, "M05", 2, 1, 1, 52, 500, 0, 0,
+ "negative fractional units rounded with correct rounding mode");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/argument-string-negative-fractional-units.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/argument-string-negative-fractional-units.js
new file mode 100644
index 0000000000..d1ce63b571
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/argument-string-negative-fractional-units.js
@@ -0,0 +1,20 @@
+// |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.plaindatetime.prototype.subtract
+description: Strings with fractional duration units are treated with the correct sign
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const instance = new Temporal.PlainDateTime(2000, 5, 2);
+
+const resultHours = instance.subtract("-PT24.567890123H");
+TemporalHelpers.assertPlainDateTime(resultHours, 2000, 5, "M05", 3, 0, 34, 4, 404, 442, 800, "negative fractional hours");
+
+const resultMinutes = instance.subtract("-PT1440.567890123M");
+TemporalHelpers.assertPlainDateTime(resultMinutes, 2000, 5, "M05", 3, 0, 0, 34, 73, 407, 380, "negative fractional minutes");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/argument-string.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/argument-string.js
new file mode 100644
index 0000000000..53f5e8101a
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/argument-string.js
@@ -0,0 +1,16 @@
+// |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.plaindatetime.prototype.subtract
+description: A string is parsed into the correct object when passed as the argument
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const instance = Temporal.PlainDateTime.from({ year: 2000, month: 5, day: 2, minute: 34, second: 56, millisecond: 987, microsecond: 654, nanosecond: 321 });
+const result = instance.subtract("P3D");
+TemporalHelpers.assertPlainDateTime(result, 2000, 4, "M04", 29, 0, 34, 56, 987, 654, 321);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/balance-negative-time-units.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/balance-negative-time-units.js
new file mode 100644
index 0000000000..fd8f37b576
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/balance-negative-time-units.js
@@ -0,0 +1,52 @@
+// |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.plaindatetime.prototype.subtract
+description: Negative time fields are balanced upwards
+info: |
+ sec-temporal-balancetime steps 3–14:
+ 3. Set _microsecond_ to _microsecond_ + floor(_nanosecond_ / 1000).
+ 4. Set _nanosecond_ to _nanosecond_ modulo 1000.
+ 5. Set _millisecond_ to _millisecond_ + floor(_microsecond_ / 1000).
+ 6. Set _microsecond_ to _microsecond_ modulo 1000.
+ 7. Set _second_ to _second_ + floor(_millisecond_ / 1000).
+ 8. Set _millisecond_ to _millisecond_ modulo 1000.
+ 9. Set _minute_ to _minute_ + floor(_second_ / 60).
+ 10. Set _second_ to _second_ modulo 60.
+ 11. Set _hour_ to _hour_ + floor(_minute_ / 60).
+ 12. Set _minute_ to _minute_ modulo 60.
+ 13. Let _days_ be floor(_hour_ / 24).
+ 14. Set _hour_ to _hour_ modulo 24.
+ sec-temporal-addtime step 8:
+ 8. Return ? BalanceTime(_hour_, _minute_, _second_, _millisecond_, _microsecond_, _nanosecond_).
+ sec-temporal-adddatetime step 1:
+ 1. Let _timeResult_ be ? AddTime(_hour_, _minute_, _second_, _millisecond_, _microsecond_, _nanosecond_, _hours_, _minutes_, _seconds_, _milliseconds_, _microseconds_, _nanoseconds_).
+ sec-temporal.plaindatetime.prototype.subtract step 5:
+ 5. Let _result_ be ? AddDateTime(_dateTime_.[[ISOYear]], _dateTime_.[[ISOMonth]], _dateTime_.[[ISODay]], _dateTime_.[[ISOHour]], _dateTime_.[[ISOMinute]], _dateTime_.[[ISOSecond]], _dateTime_.[[ISOMillisecond]], _dateTime_.[[ISOMicrosecond]], _dateTime_.[[ISONanosecond]], _dateTime_.[[Calendar]], −_duration_.[[Years]], −_duration_.[[Months]], −_duration_.[[Weeks]], −_duration_.[[Days]], −_duration_.[[Hours]], −_duration_.[[Minutes]], −_duration_.[[Seconds]], −_duration_.[[Milliseconds]], −_duration_.[[Microseconds]], −_duration_.[[Nanoseconds]], _options_).
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const datetime = new Temporal.PlainDateTime(1996, 5, 2, 1, 1, 1, 1, 1, 1);
+
+const result1 = datetime.subtract(new Temporal.Duration(0, 0, 0, 0, 0, 0, 0, 0, 0, 2));
+TemporalHelpers.assertPlainDateTime(result1, 1996, 5, "M05", 2, 1, 1, 1, 1, 0, 999, "nanoseconds balance");
+
+const result2 = datetime.subtract(new Temporal.Duration(0, 0, 0, 0, 0, 0, 0, 0, 2));
+TemporalHelpers.assertPlainDateTime(result2, 1996, 5, "M05", 2, 1, 1, 1, 0, 999, 1, "microseconds balance");
+
+const result3 = datetime.subtract(new Temporal.Duration(0, 0, 0, 0, 0, 0, 0, 2));
+TemporalHelpers.assertPlainDateTime(result3, 1996, 5, "M05", 2, 1, 1, 0, 999, 1, 1, "milliseconds balance");
+
+const result4 = datetime.subtract(new Temporal.Duration(0, 0, 0, 0, 0, 0, 2));
+TemporalHelpers.assertPlainDateTime(result4, 1996, 5, "M05", 2, 1, 0, 59, 1, 1, 1, "seconds balance");
+
+const result5 = datetime.subtract(new Temporal.Duration(0, 0, 0, 0, 0, 2));
+TemporalHelpers.assertPlainDateTime(result5, 1996, 5, "M05", 2, 0, 59, 1, 1, 1, 1, "minutes balance");
+
+const result6 = datetime.subtract(new Temporal.Duration(0, 0, 0, 0, 2));
+TemporalHelpers.assertPlainDateTime(result6, 1996, 5, "M05", 1, 23, 1, 1, 1, 1, 1, "hours balance");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/branding.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/branding.js
new file mode 100644
index 0000000000..d2bd3b7bef
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/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.plaindatetime.prototype.subtract
+description: Throw a TypeError if the receiver is invalid
+features: [Symbol, Temporal]
+---*/
+
+const subtract = Temporal.PlainDateTime.prototype.subtract;
+
+assert.sameValue(typeof subtract, "function");
+
+const args = [new Temporal.Duration(5)];
+
+assert.throws(TypeError, () => subtract.apply(undefined, args), "undefined");
+assert.throws(TypeError, () => subtract.apply(null, args), "null");
+assert.throws(TypeError, () => subtract.apply(true, args), "true");
+assert.throws(TypeError, () => subtract.apply("", args), "empty string");
+assert.throws(TypeError, () => subtract.apply(Symbol(), args), "symbol");
+assert.throws(TypeError, () => subtract.apply(1, args), "1");
+assert.throws(TypeError, () => subtract.apply({}, args), "plain object");
+assert.throws(TypeError, () => subtract.apply(Temporal.PlainDateTime, args), "Temporal.PlainDateTime");
+assert.throws(TypeError, () => subtract.apply(Temporal.PlainDateTime.prototype, args), "Temporal.PlainDateTime.prototype");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/browser.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/browser.js
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/browser.js
diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/builtin-calendar-no-observable-calls.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/builtin-calendar-no-observable-calls.js
new file mode 100644
index 0000000000..2e67ff726e
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/builtin-calendar-no-observable-calls.js
@@ -0,0 +1,28 @@
+// |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.plaindatetime.prototype.subtract
+description: >
+ Calling the method on an instance constructed with a builtin calendar causes
+ no observable lookups or calls to calendar methods.
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const dateAddOriginal = Object.getOwnPropertyDescriptor(Temporal.Calendar.prototype, "dateAdd");
+Object.defineProperty(Temporal.Calendar.prototype, "dateAdd", {
+ configurable: true,
+ enumerable: false,
+ get() {
+ TemporalHelpers.assertUnreachable("dateAdd should not be looked up");
+ },
+});
+
+const instance = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, "iso8601");
+instance.subtract(new Temporal.Duration(1));
+
+Object.defineProperty(Temporal.Calendar.prototype, "dateAdd", dateAddOriginal);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/builtin.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/builtin.js
new file mode 100644
index 0000000000..2abbf5b33f
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/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.plaindatetime.prototype.subtract
+description: >
+ Tests that Temporal.PlainDateTime.prototype.subtract
+ 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.PlainDateTime.prototype.subtract),
+ true, "Built-in objects must be extensible.");
+
+assert.sameValue(Object.prototype.toString.call(Temporal.PlainDateTime.prototype.subtract),
+ "[object Function]", "Object.prototype.toString");
+
+assert.sameValue(Object.getPrototypeOf(Temporal.PlainDateTime.prototype.subtract),
+ Function.prototype, "prototype");
+
+assert.sameValue(Temporal.PlainDateTime.prototype.subtract.hasOwnProperty("prototype"),
+ false, "prototype property");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/calendar-dateadd.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/calendar-dateadd.js
new file mode 100644
index 0000000000..7b6ec5cff6
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/calendar-dateadd.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.plaindatetime.prototype.subtract
+description: PlainDateTime.prototype.subtract should call dateAdd with the appropriate values.
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+let calls = 0;
+class CustomCalendar extends Temporal.Calendar {
+ constructor() {
+ super("iso8601");
+ }
+ dateAdd(plainDate, duration, options) {
+ ++calls;
+ TemporalHelpers.assertPlainDate(plainDate, 2020, 3, "M03", 14, "plainDate argument");
+ TemporalHelpers.assertDuration(duration, 0, -10, 0, -1, 0, 0, 0, 0, 0, 0, "duration argument");
+ assert.sameValue(typeof options, "object", "options argument: type");
+ assert.sameValue(Object.getPrototypeOf(options), null, "options argument: prototype");
+ return super.dateAdd(plainDate, duration, options);
+ }
+}
+
+const plainDateTime = new Temporal.PlainDateTime(2020, 3, 14, 12, 34, 56, 987, 654, 321, new CustomCalendar());
+const result = plainDateTime.subtract({ months: 10, hours: 14 });
+TemporalHelpers.assertPlainDateTime(result, 2019, 5, "M05", 13, 22, 34, 56, 987, 654, 321);
+assert.sameValue(calls, 1, "should have called dateAdd");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/hour-overflow.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/hour-overflow.js
new file mode 100644
index 0000000000..6da61f9205
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/hour-overflow.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.plaindatetime.prototype.subtract
+description: Testing overflow hours (subtracting hours that push one to the next/previous day)
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+const dt = new Temporal.PlainDateTime(2019, 10, 29, 10, 46, 38, 271, 986, 102);
+const later = new Temporal.PlainDateTime(2020, 5, 31, 23, 12, 38, 271, 986, 102);
+
+TemporalHelpers.assertPlainDateTime(
+ dt.subtract({ hours: 12 }),
+ 2019, 10, "M10", 28, 22, 46, 38, 271, 986, 102,
+ "subtract result"
+);
+
+TemporalHelpers.assertPlainDateTime(
+ dt.add({ hours: -12 }),
+ 2019, 10, "M10", 28, 22, 46, 38, 271, 986, 102,
+ "hour overflow (pushes to previous day)"
+);
+
+TemporalHelpers.assertPlainDateTime(
+ later.subtract({ hours: -2 }),
+ 2020, 6, "M06", 1, 1, 12, 38, 271, 986, 102,
+ "subtracting a negative amount of hours is equivalent to adding hours"
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/infinity-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/infinity-throws-rangeerror.js
new file mode 100644
index 0000000000..b91a8d9857
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/infinity-throws-rangeerror.js
@@ -0,0 +1,38 @@
+// |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.
+
+/*---
+description: Temporal.PlainDateTime.prototype.subtract throws a RangeError if any value in a property bag is Infinity
+esid: sec-temporal.plaindatetime.prototype.subtract
+features: [Temporal]
+---*/
+
+const overflows = ["constrain", "reject"];
+const fields = ["years", "months", "weeks", "days", "hours", "minutes", "seconds", "milliseconds", "microseconds", "nanoseconds"];
+
+const instance = Temporal.PlainDateTime.from({ year: 2000, month: 5, day: 2, minute: 34, second: 56, millisecond: 987, microsecond: 654, nanosecond: 321 });
+
+overflows.forEach((overflow) => {
+ fields.forEach((field) => {
+ assert.throws(RangeError, () => instance.subtract({ [field]: Infinity }, { overflow }));
+ });
+});
+
+let calls = 0;
+const obj = {
+ valueOf() {
+ calls++;
+ return Infinity;
+ }
+};
+
+overflows.forEach((overflow) => {
+ fields.forEach((field) => {
+ calls = 0;
+ assert.throws(RangeError, () => instance.subtract({ [field]: obj }, { overflow }));
+ assert.sameValue(calls, 1, "it fails after fetching the primitive value");
+ });
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/length.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/length.js
new file mode 100644
index 0000000000..ccb418cc58
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/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.plaindatetime.prototype.subtract
+description: Temporal.PlainDateTime.prototype.subtract.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.PlainDateTime.prototype.subtract, "length", {
+ value: 1,
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/limits.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/limits.js
new file mode 100644
index 0000000000..a71c40fc40
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/limits.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.plaindatetime.prototype.subtract
+description: Checking limits of representable PlainDateTime
+features: [Temporal]
+---*/
+
+const min = new Temporal.PlainDateTime(-271821, 4, 19, 0, 0, 0, 0, 0, 1);
+const max = new Temporal.PlainDateTime(275760, 9, 13, 23, 59, 59, 999, 999, 999);
+
+["reject", "constrain"].forEach((overflow) => {
+ assert.throws(
+ RangeError,
+ () => min.subtract({ nanoseconds: 1 }, { overflow }),
+ `subtracting 1 nanosecond beyond minimum limit (overflow = ${overflow})`
+ );
+ assert.throws(
+ RangeError,
+ () => max.subtract({ nanoseconds: -1 }, { overflow }),
+ `subtracting -1 nanosecond beyond maximum limit (overflow = ${overflow})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/name.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/name.js
new file mode 100644
index 0000000000..beaac9ddae
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/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.plaindatetime.prototype.subtract
+description: Temporal.PlainDateTime.prototype.subtract.name is "subtract".
+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.PlainDateTime.prototype.subtract, "name", {
+ value: "subtract",
+ writable: false,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/negative-duration.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/negative-duration.js
new file mode 100644
index 0000000000..c4bd186e02
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/negative-duration.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.plaindatetime.prototype.subtract
+description: Negative durations can be supplied
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+const jan31 = new Temporal.PlainDateTime(2020, 1, 31, 15, 0);
+
+TemporalHelpers.assertPlainDateTime(
+ jan31.subtract({ minutes: -30 }),
+ 2020, 1, "M01", 31, 15, 30, 0, 0, 0, 0,
+ "negative minutes"
+);
+
+TemporalHelpers.assertPlainDateTime(
+ jan31.subtract({ seconds: -30 }),
+ 2020, 1, "M01", 31, 15, 0, 30, 0, 0, 0,
+ "negative seconds"
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/negative-infinity-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/negative-infinity-throws-rangeerror.js
new file mode 100644
index 0000000000..e767d44cb7
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/negative-infinity-throws-rangeerror.js
@@ -0,0 +1,38 @@
+// |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.
+
+/*---
+description: Temporal.PlainDateTime.prototype.subtract throws a RangeError if any value in a property bag is -Infinity
+esid: sec-temporal.plaindatetime.prototype.subtract
+features: [Temporal]
+---*/
+
+const overflows = ["constrain", "reject"];
+const fields = ["years", "months", "weeks", "days", "hours", "minutes", "seconds", "milliseconds", "microseconds", "nanoseconds"];
+
+const instance = Temporal.PlainDateTime.from({ year: 2000, month: 5, day: 2, minute: 34, second: 56, millisecond: 987, microsecond: 654, nanosecond: 321 });
+
+overflows.forEach((overflow) => {
+ fields.forEach((field) => {
+ assert.throws(RangeError, () => instance.subtract({ [field]: -Infinity }, { overflow }));
+ });
+});
+
+let calls = 0;
+const obj = {
+ valueOf() {
+ calls++;
+ return -Infinity;
+ }
+};
+
+overflows.forEach((overflow) => {
+ fields.forEach((field) => {
+ calls = 0;
+ assert.throws(RangeError, () => instance.subtract({ [field]: obj }, { overflow }));
+ assert.sameValue(calls, 1, "it fails after fetching the primitive value");
+ });
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/non-integer-throws-rangeerror.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/non-integer-throws-rangeerror.js
new file mode 100644
index 0000000000..d9e9765eb1
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/non-integer-throws-rangeerror.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.plaindatetime.prototype.subtract
+description: A non-integer value for any recognized property in the property bag, throws a RangeError
+features: [Temporal]
+---*/
+
+const instance = new Temporal.PlainDateTime(2000, 5, 2, 15, 30, 45, 987, 654, 321);
+const fields = [
+ "years",
+ "months",
+ "weeks",
+ "days",
+ "hours",
+ "minutes",
+ "seconds",
+ "milliseconds",
+ "microseconds",
+ "nanoseconds",
+];
+fields.forEach((field) => {
+ assert.throws(RangeError, () => instance.subtract({ [field]: 1.5 }));
+ assert.throws(RangeError, () => instance.subtract({ [field]: -1.5 }));
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/not-a-constructor.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/not-a-constructor.js
new file mode 100644
index 0000000000..eef1ef6b6f
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/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.plaindatetime.prototype.subtract
+description: >
+ Temporal.PlainDateTime.prototype.subtract 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.PlainDateTime.prototype.subtract();
+}, "Calling as constructor");
+
+assert.sameValue(isConstructor(Temporal.PlainDateTime.prototype.subtract), false,
+ "isConstructor(Temporal.PlainDateTime.prototype.subtract)");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/options-empty.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/options-empty.js
new file mode 100644
index 0000000000..a26714caef
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/options-empty.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.plaindatetime.prototype.subtract
+description: Verify that undefined options are handled correctly.
+features: [Temporal]
+includes: [temporalHelpers.js]
+---*/
+
+const jan31 = new Temporal.PlainDateTime(2020, 1, 31, 15, 0);
+
+TemporalHelpers.assertPlainDateTime(
+ jan31.subtract({ months: 2 }, {}),
+ 2019, 11, "M11", 30, 15, 0, 0, 0, 0, 0,
+ "options may be empty object"
+);
+
+TemporalHelpers.assertPlainDateTime(
+ jan31.subtract({ months: 2 }, () => {}),
+ 2019, 11, "M11", 30, 15, 0, 0, 0, 0, 0,
+ "options may be function object"
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/options-invalid.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/options-invalid.js
new file mode 100644
index 0000000000..9fc78fd1aa
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/options-invalid.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.plaindatetime.prototype.subtract
+description: Various invalid (wrong type) values for options argument
+features: [Temporal, Symbol]
+---*/
+
+const jan31 = new Temporal.PlainDateTime(2020, 1, 31, 15, 0);
+
+const badOptions = [null, 1, 'hello', true, Symbol('foo'), 1n];
+
+badOptions.forEach((bad) => {
+ assert.throws(
+ TypeError,
+ () => jan31.subtract({ years: 1 }, bad),
+ `invalid options (${typeof bad})`
+ );
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/options-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/options-undefined.js
new file mode 100644
index 0000000000..81f22694a9
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/options-undefined.js
@@ -0,0 +1,22 @@
+// |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.plaindatetime.prototype.subtract
+description: Verify that undefined options are handled correctly.
+features: [Temporal]
+---*/
+
+const datetime = new Temporal.PlainDateTime(2000, 3, 31, 12, 34, 56, 987, 654, 321);
+const duration = { months: 1 };
+
+const explicit = datetime.subtract(duration, undefined);
+assert.sameValue(explicit.month, 2, "default overflow is constrain");
+assert.sameValue(explicit.day, 29, "default overflow is constrain");
+
+const implicit = datetime.subtract(duration);
+assert.sameValue(implicit.month, 2, "default overflow is constrain");
+assert.sameValue(implicit.day, 29, "default overflow is constrain");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/options-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/options-wrong-type.js
new file mode 100644
index 0000000000..bea427754a
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/options-wrong-type.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.plaindatetime.prototype.subtract
+description: TypeError thrown when options argument is a primitive
+features: [BigInt, Symbol, Temporal]
+---*/
+
+const badOptions = [
+ null,
+ true,
+ "some string",
+ Symbol(),
+ 1,
+ 2n,
+];
+
+const instance = new Temporal.PlainDateTime(2000, 5, 2);
+for (const value of badOptions) {
+ assert.throws(TypeError, () => instance.subtract({ months: 1 }, value),
+ `TypeError on wrong options type ${typeof value}`);
+};
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/order-of-operations.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/order-of-operations.js
new file mode 100644
index 0000000000..2dff5bdcf7
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/order-of-operations.js
@@ -0,0 +1,127 @@
+// |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.plaindatetime.prototype.subtract
+description: Properties on an object passed to subtract() are accessed in the correct order
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const expected = [
+ // ToTemporalDurationRecord
+ "get fields.days",
+ "get fields.days.valueOf",
+ "call fields.days.valueOf",
+ "get fields.hours",
+ "get fields.hours.valueOf",
+ "call fields.hours.valueOf",
+ "get fields.microseconds",
+ "get fields.microseconds.valueOf",
+ "call fields.microseconds.valueOf",
+ "get fields.milliseconds",
+ "get fields.milliseconds.valueOf",
+ "call fields.milliseconds.valueOf",
+ "get fields.minutes",
+ "get fields.minutes.valueOf",
+ "call fields.minutes.valueOf",
+ "get fields.months",
+ "get fields.months.valueOf",
+ "call fields.months.valueOf",
+ "get fields.nanoseconds",
+ "get fields.nanoseconds.valueOf",
+ "call fields.nanoseconds.valueOf",
+ "get fields.seconds",
+ "get fields.seconds.valueOf",
+ "call fields.seconds.valueOf",
+ "get fields.weeks",
+ "get fields.weeks.valueOf",
+ "call fields.weeks.valueOf",
+ "get fields.years",
+ "get fields.years.valueOf",
+ "call fields.years.valueOf",
+ // AddDateTime -> AddDate
+ "get this.calendar.dateAdd",
+ "call this.calendar.dateAdd",
+ // inside Calendar.p.dateAdd
+ "get options.overflow",
+ "get options.overflow.toString",
+ "call options.overflow.toString",
+];
+const actual = [];
+
+const calendar = TemporalHelpers.calendarObserver(actual, "this.calendar");
+const instance = new Temporal.PlainDateTime(2000, 5, 2, 12, 34, 56, 987, 654, 321, calendar);
+// clear observable operations that occurred during the constructor call
+actual.splice(0);
+
+const fields = TemporalHelpers.propertyBagObserver(actual, {
+ years: 1,
+ months: 1,
+ weeks: 1,
+ days: 1,
+ hours: 1,
+ minutes: 1,
+ seconds: 1,
+ milliseconds: 1,
+ microseconds: 1,
+ nanoseconds: 1,
+}, "fields");
+
+const options = TemporalHelpers.propertyBagObserver(actual, { overflow: "constrain" }, "options");
+
+instance.subtract(fields, options);
+assert.compareArray(actual, expected, "order of operations");
+
+actual.splice(0); // clear
+
+const noCalendarExpected = [
+ // ToTemporalDurationRecord
+ "get fields.days",
+ "get fields.days.valueOf",
+ "call fields.days.valueOf",
+ "get fields.hours",
+ "get fields.hours.valueOf",
+ "call fields.hours.valueOf",
+ "get fields.microseconds",
+ "get fields.microseconds.valueOf",
+ "call fields.microseconds.valueOf",
+ "get fields.milliseconds",
+ "get fields.milliseconds.valueOf",
+ "call fields.milliseconds.valueOf",
+ "get fields.minutes",
+ "get fields.minutes.valueOf",
+ "call fields.minutes.valueOf",
+ "get fields.months",
+ "get fields.nanoseconds",
+ "get fields.nanoseconds.valueOf",
+ "call fields.nanoseconds.valueOf",
+ "get fields.seconds",
+ "get fields.seconds.valueOf",
+ "call fields.seconds.valueOf",
+ "get fields.weeks",
+ "get fields.years",
+ "get this.calendar.dateAdd",
+ // AddDateTime -> AddDate
+ "get options.overflow",
+ "get options.overflow.toString",
+ "call options.overflow.toString",
+];
+
+const noCalendarFields = TemporalHelpers.propertyBagObserver(actual, {
+ days: 1,
+ hours: 1,
+ minutes: 1,
+ seconds: 1,
+ milliseconds: 1,
+ microseconds: 1,
+ nanoseconds: 1,
+}, "fields");
+
+instance.subtract(noCalendarFields, options);
+assert.compareArray(actual, noCalendarExpected, "order of operations with no calendar operation");
+
+actual.splice(0); // clear
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/overflow-invalid-string.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/overflow-invalid-string.js
new file mode 100644
index 0000000000..65a10f333f
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/overflow-invalid-string.js
@@ -0,0 +1,33 @@
+// |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.plaindatetime.prototype.subtract
+description: RangeError thrown when overflow option not one of the allowed string values
+info: |
+ sec-getoption step 10:
+ 10. If _values_ is not *undefined* and _values_ does not contain an element equal to _value_, throw a *RangeError* exception.
+ sec-temporal-totemporaloverflow step 1:
+ 1. Return ? GetOption(_normalizedOptions_, *"overflow"*, « String », « *"constrain"*, *"reject"* », *"constrain"*).
+ sec-temporal.calendar.prototype.dateadd step 7:
+ 7. Let _overflow_ be ? ToTemporalOverflow(_options_).
+ sec-temporal-adddatetime step 4:
+ 4. Let _addedDate_ be ? CalendarDateAdd(_calendar_, _datePart_, _dateDuration_, _options_).
+ sec-temporal.plaindatetime.prototype.subtract step 5:
+ 5. Let _result_ be ? AddDateTime(_dateTime_.[[ISOYear]], _dateTime_.[[ISOMonth]], _dateTime_.[[ISODay]], _dateTime_.[[ISOHour]], _dateTime_.[[ISOMinute]], _dateTime_.[[ISOSecond]], _dateTime_.[[ISOMillisecond]], _dateTime_.[[ISOMicrosecond]], _dateTime_.[[ISONanosecond]], _dateTime_.[[Calendar]], −_duration_.[[Years]], −_duration_.[[Months]], −_duration_.[[Weeks]], −_duration_.[[Days]], −_duration_.[[Hours]], −_duration_.[[Minutes]], −_duration_.[[Seconds]], −_duration_.[[Milliseconds]], −_duration_.[[Microseconds]], −_duration_.[[Nanoseconds]], _options_).
+features: [Temporal]
+---*/
+
+const date = new Temporal.PlainDateTime(2000, 5, 2, 12);
+const duration = new Temporal.Duration(3, 3, 0, 3, 3);
+const badOverflows = ["", "CONSTRAIN", "balance", "other string", "constra\u0131n", "reject\0"];
+for (const overflow of badOverflows) {
+ assert.throws(
+ RangeError,
+ () => date.subtract(duration, { overflow }),
+ `invalid overflow ("${overflow}")`
+ );
+}
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/overflow-undefined.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/overflow-undefined.js
new file mode 100644
index 0000000000..ddcfaf39fa
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/overflow-undefined.js
@@ -0,0 +1,31 @@
+// |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.plaindate.prototype.subtract
+description: Fallback value for overflow option
+info: |
+ sec-getoption step 3:
+ 3. If _value_ is *undefined*, return _fallback_.
+ sec-temporal-totemporaloverflow step 1:
+ 1. Return ? GetOption(_normalizedOptions_, *"overflow"*, « String », « *"constrain"*, *"reject"* », *"constrain"*).
+ sec-temporal.calendar.prototype.dateadd step 7:
+ 7. Let _overflow_ be ? ToTemporalOverflow(_options_).
+ sec-temporal-adddatetime step 4:
+ 4. Let _addedDate_ be ? CalendarDateAdd(_calendar_, _datePart_, _dateDuration_, _options_).
+ sec-temporal.plaindatetime.prototype.subtract step 5:
+ 5. Let _result_ be ? AddDateTime(_dateTime_.[[ISOYear]], _dateTime_.[[ISOMonth]], _dateTime_.[[ISODay]], _dateTime_.[[ISOHour]], _dateTime_.[[ISOMinute]], _dateTime_.[[ISOSecond]], _dateTime_.[[ISOMillisecond]], _dateTime_.[[ISOMicrosecond]], _dateTime_.[[ISONanosecond]], _dateTime_.[[Calendar]], −_duration_.[[Years]], −_duration_.[[Months]], −_duration_.[[Weeks]], −_duration_.[[Days]], −_duration_.[[Hours]], −_duration_.[[Minutes]], −_duration_.[[Seconds]], −_duration_.[[Milliseconds]], −_duration_.[[Microseconds]], −_duration_.[[Nanoseconds]], _options_).
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const datetime = new Temporal.PlainDateTime(2000, 5, 31, 12);
+const duration = new Temporal.Duration(3, 1);
+
+const explicit = datetime.subtract(duration, { overflow: undefined });
+TemporalHelpers.assertPlainDateTime(explicit, 1997, 4, "M04", 30, 12, 0, 0, 0, 0, 0, "default overflow is constrain");
+const implicit = datetime.subtract(duration, {});
+TemporalHelpers.assertPlainDateTime(implicit, 1997, 4, "M04", 30, 12, 0, 0, 0, 0, 0, "default overflow is constrain");
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/overflow-wrong-type.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/overflow-wrong-type.js
new file mode 100644
index 0000000000..debacd548a
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/overflow-wrong-type.js
@@ -0,0 +1,30 @@
+// |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.plaindatetime.prototype.subtract
+description: Type conversions for overflow option
+info: |
+ sec-getoption step 9.a:
+ a. Set _value_ to ? ToString(_value_).
+ sec-temporal-totemporaloverflow step 1:
+ 1. Return ? GetOption(_normalizedOptions_, *"overflow"*, « String », « *"constrain"*, *"reject"* », *"constrain"*).
+ sec-temporal.calendar.prototype.dateadd step 7:
+ 7. Let _overflow_ be ? ToTemporalOverflow(_options_).
+ sec-temporal-adddatetime step 4:
+ 4. Let _addedDate_ be ? CalendarDateAdd(_calendar_, _datePart_, _dateDuration_, _options_).
+ sec-temporal.plaindatetime.prototype.subtract step 5:
+ 5. Let _result_ be ? AddDateTime(_dateTime_.[[ISOYear]], _dateTime_.[[ISOMonth]], _dateTime_.[[ISODay]], _dateTime_.[[ISOHour]], _dateTime_.[[ISOMinute]], _dateTime_.[[ISOSecond]], _dateTime_.[[ISOMillisecond]], _dateTime_.[[ISOMicrosecond]], _dateTime_.[[ISONanosecond]], _dateTime_.[[Calendar]], −_duration_.[[Years]], −_duration_.[[Months]], −_duration_.[[Weeks]], −_duration_.[[Days]], −_duration_.[[Hours]], −_duration_.[[Minutes]], −_duration_.[[Seconds]], −_duration_.[[Milliseconds]], −_duration_.[[Microseconds]], −_duration_.[[Nanoseconds]], _options_).
+includes: [compareArray.js, temporalHelpers.js]
+features: [Temporal]
+---*/
+
+const datetime = new Temporal.PlainDateTime(2000, 5, 2, 12);
+const duration = new Temporal.Duration(3, 3, 0, 3, 3);
+TemporalHelpers.checkStringOptionWrongType("overflow", "constrain",
+ (overflow) => datetime.subtract(duration, { overflow }),
+ (result, descr) => TemporalHelpers.assertPlainDateTime(result, 1997, 1, "M01", 30, 9, 0, 0, 0, 0, 0, descr),
+);
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/prop-desc.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/prop-desc.js
new file mode 100644
index 0000000000..19a42d65fa
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/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.plaindatetime.prototype.subtract
+description: The "subtract" property of Temporal.PlainDateTime.prototype
+includes: [propertyHelper.js]
+features: [Temporal]
+---*/
+
+assert.sameValue(
+ typeof Temporal.PlainDateTime.prototype.subtract,
+ "function",
+ "`typeof PlainDateTime.prototype.subtract` is `function`"
+);
+
+verifyProperty(Temporal.PlainDateTime.prototype, "subtract", {
+ writable: true,
+ enumerable: false,
+ configurable: true,
+});
+
+reportCompare(0, 0);
diff --git a/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/shell.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/shell.js
new file mode 100644
index 0000000000..eda1477282
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/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/PlainDateTime/prototype/subtract/subclassing-ignored.js b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/subclassing-ignored.js
new file mode 100644
index 0000000000..7bc53d362e
--- /dev/null
+++ b/js/src/tests/test262/built-ins/Temporal/PlainDateTime/prototype/subtract/subclassing-ignored.js
@@ -0,0 +1,20 @@
+// |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.plaindatetime.prototype.subtract
+description: Objects of a subclass are never created as return values for subtract()
+includes: [temporalHelpers.js]
+features: [Temporal]
+---*/
+
+TemporalHelpers.checkSubclassingIgnored(
+ Temporal.PlainDateTime,
+ [2000, 5, 2, 12, 34, 56, 987, 654, 321],
+ "subtract",
+ [{ nanoseconds: 1 }],
+ (result) => TemporalHelpers.assertPlainDateTime(result, 2000, 5, "M05", 2, 12, 34, 56, 987, 654, 320),
+);
+
+reportCompare(0, 0);