From e574d1a7b358b4f97ae3da1da0f1b875c4cf78f3 Mon Sep 17 00:00:00 2001 From: Philip Chimento Date: Mon, 18 May 2020 17:21:57 -0700 Subject: [PATCH] Add equals() method This adds an equals() method to Absolute, Date, DateTime, MonthDay, Time, and YearMonth. For types with a compare() method, `a.equals(b)` is equivalent to `Temporal.X.compare(a, b) === 0` Duration doesn't have an equals() method at this time because, does `{ minutes: 1, seconds: 30 }` equal `{ seconds: 90 }`? TimeZone doesn't have one either because it's simple enough to compare the .name property. --- docs/absolute.md | 21 +++++++++++++ docs/date.md | 23 ++++++++++++++ docs/datetime.md | 23 ++++++++++++++ docs/monthday.md | 21 +++++++++++++ docs/time.md | 21 +++++++++++++ docs/yearmonth.md | 23 ++++++++++++++ polyfill/lib/absolute.mjs | 7 +++++ polyfill/lib/date.mjs | 10 +++++++ polyfill/lib/datetime.mjs | 10 +++++++ polyfill/lib/monthday.mjs | 10 +++++++ polyfill/lib/time.mjs | 10 +++++++ polyfill/lib/yearmonth.mjs | 10 +++++++ .../prototype/equals/argument-wrong-type.js | 19 ++++++++++++ .../Absolute/prototype/equals/branding.js | 21 +++++++++++++ .../Absolute/prototype/equals/prop-desc.js | 19 ++++++++++++ .../prototype/equals/argument-wrong-type.js | 19 ++++++++++++ .../test/Date/prototype/equals/branding.js | 21 +++++++++++++ .../test/Date/prototype/equals/prop-desc.js | 18 +++++++++++ .../prototype/equals/argument-wrong-type.js | 19 ++++++++++++ .../DateTime/prototype/equals/branding.js | 21 +++++++++++++ .../DateTime/prototype/equals/prop-desc.js | 19 ++++++++++++ .../prototype/equals/argument-wrong-type.js | 19 ++++++++++++ .../MonthDay/prototype/equals/branding.js | 21 +++++++++++++ .../MonthDay/prototype/equals/prop-desc.js | 19 ++++++++++++ .../prototype/equals/argument-wrong-type.js | 19 ++++++++++++ .../test/Time/prototype/equals/branding.js | 21 +++++++++++++ .../test/Time/prototype/equals/prop-desc.js | 19 ++++++++++++ .../prototype/equals/argument-wrong-type.js | 19 ++++++++++++ .../YearMonth/prototype/equals/branding.js | 21 +++++++++++++ .../YearMonth/prototype/equals/prop-desc.js | 19 ++++++++++++ polyfill/test/absolute.mjs | 30 ++++++++++++++++--- polyfill/test/date.mjs | 17 +++++++++-- polyfill/test/datemath.mjs | 7 ++--- polyfill/test/datetime.mjs | 19 ++++++++++-- polyfill/test/monthday.mjs | 19 ++++++++++-- polyfill/test/time.mjs | 15 +++++++++- polyfill/test/yearmonth.mjs | 19 ++++++++++-- spec/absolute.html | 15 ++++++++++ spec/date.html | 17 +++++++++++ spec/datetime.html | 23 ++++++++++++++ spec/monthday.html | 16 ++++++++++ spec/time.html | 20 +++++++++++++ spec/yearmonth.html | 16 ++++++++++ 43 files changed, 754 insertions(+), 21 deletions(-) create mode 100644 polyfill/test/Absolute/prototype/equals/argument-wrong-type.js create mode 100644 polyfill/test/Absolute/prototype/equals/branding.js create mode 100644 polyfill/test/Absolute/prototype/equals/prop-desc.js create mode 100644 polyfill/test/Date/prototype/equals/argument-wrong-type.js create mode 100644 polyfill/test/Date/prototype/equals/branding.js create mode 100644 polyfill/test/Date/prototype/equals/prop-desc.js create mode 100644 polyfill/test/DateTime/prototype/equals/argument-wrong-type.js create mode 100644 polyfill/test/DateTime/prototype/equals/branding.js create mode 100644 polyfill/test/DateTime/prototype/equals/prop-desc.js create mode 100644 polyfill/test/MonthDay/prototype/equals/argument-wrong-type.js create mode 100644 polyfill/test/MonthDay/prototype/equals/branding.js create mode 100644 polyfill/test/MonthDay/prototype/equals/prop-desc.js create mode 100644 polyfill/test/Time/prototype/equals/argument-wrong-type.js create mode 100644 polyfill/test/Time/prototype/equals/branding.js create mode 100644 polyfill/test/Time/prototype/equals/prop-desc.js create mode 100644 polyfill/test/YearMonth/prototype/equals/argument-wrong-type.js create mode 100644 polyfill/test/YearMonth/prototype/equals/branding.js create mode 100644 polyfill/test/YearMonth/prototype/equals/prop-desc.js diff --git a/docs/absolute.md b/docs/absolute.md index ab73297033..247ca54dfa 100644 --- a/docs/absolute.md +++ b/docs/absolute.md @@ -334,6 +334,27 @@ epoch.inTimeZone(utc).difference(billion.inTimeZone(utc), { largestUnit: 'years' // => P31Y8M8DT1H46M40S ``` +### absolute.**equals**(_other_: Temporal.Absolute) : boolean + +**Parameters:** +- `other` (`Temporal.Absolute`): Another time to compare. + +**Returns:** `true` if `absolute` and `other` are equal, or `false` if not. + +Compares two `Temporal.Absolute` objects for equality. + +This function exists because it's not possible to compare using `absolute == other` or `absolute === other`, due to ambiguity in the primitive representation and between Temporal types. + +If you don't need to know the order in which the two times occur, then this function may be less typing and more efficient than `Temporal.Absolute.compare`. + +Example usage: +```javascript +one = Temporal.Absolute.fromEpochSeconds(1.0e9); +two = Temporal.Absolute.fromEpochSeconds(1.1e9); +one.equals(two) // => false +one.equals(one) // => true +``` + ### absolute.**toString**(_timeZone_?: Temporal.TimeZone | string) : string **Parameters:** diff --git a/docs/date.md b/docs/date.md index 76a16477fc..f1fbe8b57f 100644 --- a/docs/date.md +++ b/docs/date.md @@ -371,6 +371,29 @@ date.withTime(midnight).difference(other.withTime(midnight), { largestUnit: 'hou // => PT109032H ``` +### date.**equals**(_other_: Temporal.Date) : boolean + +**Parameters:** +- `other` (`Temporal.Date`): Another date to compare. + +**Returns:** `true` if `date` and `other` are equal, or `false` if not. + +Compares two `Temporal.Date` objects for equality. + +This function exists because it's not possible to compare using `date == other` or `date === other`, due to ambiguity in the primitive representation and between Temporal types. + +If you don't need to know the order in which the two dates occur, then this function may be less typing and more efficient than `Temporal.Date.compare`. + +Note that this function will return `true` if the two dates are equal, even if they are expressed in different calendar systems. + +Example usage: +```javascript +date = Temporal.Date.from('2006-08-24'); +other = Temporal.Date.from('2019-01-31'); +date.equals(other) // => false +date.equals(date) // => true +``` + ### date.**toString**() : string **Returns:** a string in the ISO 8601 date format representing `date`. diff --git a/docs/datetime.md b/docs/datetime.md index 0e02b19de8..2c1bbee363 100644 --- a/docs/datetime.md +++ b/docs/datetime.md @@ -429,6 +429,29 @@ feb1.difference(mar1); // => P29D feb1.difference(mar1, { largestUnit: 'months' }); // => P1M ``` +### datetime.**equals**(_other_: Temporal.DateTime) : boolean + +**Parameters:** +- `other` (`Temporal.DateTime`): Another date/time to compare. + +**Returns:** `true` if `datetime` and `other` are equal, or `false` if not. + +Compares two `Temporal.DateTime` objects for equality. + +This function exists because it's not possible to compare using `datetime == other` or `datetime === other`, due to ambiguity in the primitive representation and between Temporal types. + +If you don't need to know the order in which the two dates/times occur, then this function may be less typing and more efficient than `Temporal.DateTime.compare`. + +Note that this function will return `true` if the two date/times are equal, even if they are expressed in different calendar systems. + +Example usage: +```javascript +dt1 = Temporal.DateTime.from('1995-12-07T03:24:30.000003500'); +dt2 = Temporal.DateTime.from('2019-01-31T15:30'); +dt1.equals(dt2) // => false +dt1.equals(dt1) // => true +``` + ### datetime.**toString**() : string **Returns:** a string in the ISO 8601 date format representing `datetime`. diff --git a/docs/monthday.md b/docs/monthday.md index b583a9eb60..b97ef01eb4 100644 --- a/docs/monthday.md +++ b/docs/monthday.md @@ -150,6 +150,27 @@ md.with({ day: 31 }) // => 11-30 Temporal.MonthDay.from('02-01').with({ day: 31 }); // => 02-29 ``` +### monthDay.**equals**(_other_: Temporal.MonthDay) : boolean + +**Parameters:** +- `other` (`Temporal.MonthDay`): Another month-day to compare. + +**Returns:** `true` if `monthDay` and `other` are equal, or `false` if not. + +Compares two `Temporal.MonthDay` objects for equality. + +This function exists because it's not possible to compare using `monthDay == other` or `monthDay === other`, due to ambiguity in the primitive representation and between Temporal types. + +Note that two `Temporal.MonthDay`s expressed in different calendar systems can never be equal, because it's impossible to tell whether they fall on the same day without knowing the year. + +Example usage: +```javascript +dt1 = Temporal.DateTime.from('1995-12-07T03:24:30.000003500'); +dt2 = Temporal.DateTime.from('2019-01-31T15:30'); +dt1.equals(dt2) // => false +dt1.equals(dt1) // => true +``` + ### monthDay.**toString**() : string **Returns:** a string in the ISO 8601 date format representing `monthDay`. diff --git a/docs/time.md b/docs/time.md index 7944f368ef..ac35575c2f 100644 --- a/docs/time.md +++ b/docs/time.md @@ -270,6 +270,27 @@ time.difference(Temporal.Time.from('20:13:20.971398099')) // => PT34M11.9030518 Temporal.Time.from('01:00').difference(Temporal.Time.from('23:00')) // => P2H ``` +### time.**equals**(_other_: Temporal.Time) : boolean + +**Parameters:** +- `other` (`Temporal.Time`): Another time to compare. + +**Returns:** `true` if `time` and `other` are equal, or `false` if not. + +Compares two `Temporal.Time` objects for equality. + +This function exists because it's not possible to compare using `time == other` or `time === other`, due to ambiguity in the primitive representation and between Temporal types. + +If you don't need to know the order in which the two dates occur, then this function may be less typing and more efficient than `Temporal.Time.compare`. + +Example usage: +```javascript +time = Temporal.Time.from('19:39:09.068346205'); +other = Temporal.Time.from('20:13:20.971398099'); +time.equals(other) // => false +time.equals(time) // => true +``` + ### time.**toString**() : string **Returns:** a string in the ISO 8601 time format representing `time`. diff --git a/docs/yearmonth.md b/docs/yearmonth.md index 2182bbe83b..d6696e3747 100644 --- a/docs/yearmonth.md +++ b/docs/yearmonth.md @@ -313,6 +313,29 @@ ym.difference(other, { largestUnit: 'months' }) // => P154M ym.withDay(1).difference(other.withDay(1), { largestUnit: 'days' }); // => P4687D ``` +### yearMonth.**equals**(_other_: Temporal.YearMonth) : boolean + +**Parameters:** +- `other` (`Temporal.YearMonth`): Another month to compare. + +**Returns:** `true` if `yearMonth` and `other` are equal, or `false` if not. + +Compares two `Temporal.YearMonth` objects for equality. + +This function exists because it's not possible to compare using `yearMonth == other` or `yearMonth === other`, due to ambiguity in the primitive representation and between Temporal types. + +Note that equality of two months from different calendar systems only makes sense in a few cases, such as when the two calendar systems both use the Gregorian year. + +Even if you are using the same calendar system, if you don't need to know the order in which the two months occur, then this function may be less typing and more efficient than `Temporal.YearMonth.compare`. + +Example usage: +```javascript +ym = Temporal.YearMonth.from('2019-06'); +other = Temporal.YearMonth.from('2006-08'); +ym.equals(other) // => false +ym.equals(ym) // => true +``` + ### yearMonth.**toString**() : string **Returns:** a string in the ISO 8601 date format representing `yearMonth`. diff --git a/polyfill/lib/absolute.mjs b/polyfill/lib/absolute.mjs index 17755384df..86973e28c5 100644 --- a/polyfill/lib/absolute.mjs +++ b/polyfill/lib/absolute.mjs @@ -118,6 +118,13 @@ export class Absolute { ); return new Duration(0, 0, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds); } + equals(other) { + if (!ES.IsTemporalAbsolute(this)) throw new TypeError('invalid receiver'); + if (!ES.IsTemporalAbsolute(other)) throw new TypeError('invalid Absolute object'); + const one = GetSlot(this, EPOCHNANOSECONDS); + const two = GetSlot(other, EPOCHNANOSECONDS); + return bigInt(one).equals(two); + } toString(temporalTimeZoneLike = 'UTC') { if (!ES.IsTemporalAbsolute(this)) throw new TypeError('invalid receiver'); const timeZone = ES.ToTemporalTimeZone(temporalTimeZoneLike); diff --git a/polyfill/lib/date.mjs b/polyfill/lib/date.mjs index a8c3902f8a..731e835bc6 100644 --- a/polyfill/lib/date.mjs +++ b/polyfill/lib/date.mjs @@ -131,6 +131,16 @@ export class Date { const Duration = GetIntrinsic('%Temporal.Duration%'); return new Duration(years, months, days, 0, 0, 0, 0, 0, 0); } + equals(other) { + if (!ES.IsTemporalDate(this)) throw new TypeError('invalid receiver'); + if (!ES.IsTemporalDate(other)) throw new TypeError('invalid Date object'); + for (const slot of [ISO_YEAR, ISO_MONTH, ISO_DAY]) { + const val1 = GetSlot(this, slot); + const val2 = GetSlot(other, slot); + if (val1 !== val2) return false; + } + return true; + } toString() { if (!ES.IsTemporalDate(this)) throw new TypeError('invalid receiver'); let year = ES.ISOYearString(GetSlot(this, ISO_YEAR)); diff --git a/polyfill/lib/datetime.mjs b/polyfill/lib/datetime.mjs index fc63c60dc0..e84ef56562 100644 --- a/polyfill/lib/datetime.mjs +++ b/polyfill/lib/datetime.mjs @@ -269,6 +269,16 @@ export class DateTime { const Duration = GetIntrinsic('%Temporal.Duration%'); return new Duration(years, months, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds); } + equals(other) { + if (!ES.IsTemporalDateTime(this)) throw new TypeError('invalid receiver'); + if (!ES.IsTemporalDateTime(other)) throw new TypeError('invalid Date object'); + for (const slot of [ISO_YEAR, ISO_MONTH, ISO_DAY, HOUR, MINUTE, SECOND, MILLISECOND, MICROSECOND, NANOSECOND]) { + const val1 = GetSlot(this, slot); + const val2 = GetSlot(other, slot); + if (val1 !== val2) return false; + } + return true; + } toString() { if (!ES.IsTemporalDateTime(this)) throw new TypeError('invalid receiver'); let year = ES.ISOYearString(GetSlot(this, ISO_YEAR)); diff --git a/polyfill/lib/monthday.mjs b/polyfill/lib/monthday.mjs index 3039ec78b3..fe64229a64 100644 --- a/polyfill/lib/monthday.mjs +++ b/polyfill/lib/monthday.mjs @@ -37,6 +37,16 @@ export class MonthDay { if (!ES.IsTemporalMonthDay(result)) throw new TypeError('invalid result'); return result; } + equals(other) { + if (!ES.IsTemporalMonthDay(this)) throw new TypeError('invalid receiver'); + if (!ES.IsTemporalMonthDay(other)) throw new TypeError('invalid MonthDay object'); + for (const slot of [ISO_MONTH, ISO_DAY]) { + const val1 = GetSlot(this, slot); + const val2 = GetSlot(other, slot); + if (val1 !== val2) return false; + } + return true; + } toString() { if (!ES.IsTemporalMonthDay(this)) throw new TypeError('invalid receiver'); let month = ES.ISODateTimePartString(GetSlot(this, ISO_MONTH)); diff --git a/polyfill/lib/time.mjs b/polyfill/lib/time.mjs index 3b78a2861b..af0345f103 100644 --- a/polyfill/lib/time.mjs +++ b/polyfill/lib/time.mjs @@ -191,6 +191,16 @@ export class Time { const Duration = GetIntrinsic('%Temporal.Duration%'); return new Duration(0, 0, 0, hours, minutes, seconds, milliseconds, microseconds, nanoseconds); } + equals(other) { + if (!ES.IsTemporalTime(this)) throw new TypeError('invalid receiver'); + if (!ES.IsTemporalTime(other)) throw new TypeError('invalid Time object'); + for (const slot of [HOUR, MINUTE, SECOND, MILLISECOND, MICROSECOND, NANOSECOND]) { + const val1 = GetSlot(this, slot); + const val2 = GetSlot(other, slot); + if (val1 !== val2) return false; + } + return true; + } toString() { if (!ES.IsTemporalTime(this)) throw new TypeError('invalid receiver'); diff --git a/polyfill/lib/yearmonth.mjs b/polyfill/lib/yearmonth.mjs index 555d8762bf..db56183d06 100644 --- a/polyfill/lib/yearmonth.mjs +++ b/polyfill/lib/yearmonth.mjs @@ -112,6 +112,16 @@ export class YearMonth { const Duration = GetIntrinsic('%Temporal.Duration%'); return new Duration(years, months); } + equals(other) { + if (!ES.IsTemporalYearMonth(this)) throw new TypeError('invalid receiver'); + if (!ES.IsTemporalYearMonth(other)) throw new TypeError('invalid YearMonth object'); + for (const slot of [ISO_YEAR, ISO_MONTH]) { + const val1 = GetSlot(this, slot); + const val2 = GetSlot(other, slot); + if (val1 !== val2) return false; + } + return true; + } toString() { if (!ES.IsTemporalYearMonth(this)) throw new TypeError('invalid receiver'); let year = ES.ISOYearString(GetSlot(this, ISO_YEAR)); diff --git a/polyfill/test/Absolute/prototype/equals/argument-wrong-type.js b/polyfill/test/Absolute/prototype/equals/argument-wrong-type.js new file mode 100644 index 0000000000..b421d193ec --- /dev/null +++ b/polyfill/test/Absolute/prototype/equals/argument-wrong-type.js @@ -0,0 +1,19 @@ +// 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.absolute.prototype.equals +features: [Symbol] +---*/ + +const instance = Temporal.Absolute.fromEpochSeconds(0); + +assert.throws(TypeError, () => instance.equals(undefined), "undefined"); +assert.throws(TypeError, () => instance.equals(null), "null"); +assert.throws(TypeError, () => instance.equals(true), "true"); +assert.throws(TypeError, () => instance.equals(""), "empty string"); +assert.throws(TypeError, () => instance.equals(Symbol()), "symbol"); +assert.throws(TypeError, () => instance.equals(1), "1"); +assert.throws(TypeError, () => instance.equals({}), "plain object"); +assert.throws(TypeError, () => instance.equals(Temporal.Absolute), "Temporal.Absolute"); +assert.throws(TypeError, () => instance.equals(Temporal.Absolute.prototype), "Temporal.Absolute.prototype"); diff --git a/polyfill/test/Absolute/prototype/equals/branding.js b/polyfill/test/Absolute/prototype/equals/branding.js new file mode 100644 index 0000000000..a2fb2a2c58 --- /dev/null +++ b/polyfill/test/Absolute/prototype/equals/branding.js @@ -0,0 +1,21 @@ +// 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.absolute.prototype.equals +features: [Symbol] +---*/ + +const equals = Temporal.Absolute.prototype.equals; + +assert.sameValue(typeof equals, "function"); + +assert.throws(TypeError, () => equals.call(undefined), "undefined"); +assert.throws(TypeError, () => equals.call(null), "null"); +assert.throws(TypeError, () => equals.call(true), "true"); +assert.throws(TypeError, () => equals.call(""), "empty string"); +assert.throws(TypeError, () => equals.call(Symbol()), "symbol"); +assert.throws(TypeError, () => equals.call(1), "1"); +assert.throws(TypeError, () => equals.call({}), "plain object"); +assert.throws(TypeError, () => equals.call(Temporal.Absolute), "Temporal.Absolute"); +assert.throws(TypeError, () => equals.call(Temporal.Absolute.prototype), "Temporal.Absolute.prototype"); diff --git a/polyfill/test/Absolute/prototype/equals/prop-desc.js b/polyfill/test/Absolute/prototype/equals/prop-desc.js new file mode 100644 index 0000000000..b3668fa9ed --- /dev/null +++ b/polyfill/test/Absolute/prototype/equals/prop-desc.js @@ -0,0 +1,19 @@ +// Copyright (C) 2020 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +includes: [propertyHelper.js] +---*/ + +const { Absolute } = Temporal; +assert.sameValue( + typeof Absolute.prototype.equals, + "function", + "`typeof Absolute.prototype.equals` is `function`" +); + +verifyProperty(Absolute.prototype, "equals", { + writable: true, + enumerable: false, + configurable: true, +}); diff --git a/polyfill/test/Date/prototype/equals/argument-wrong-type.js b/polyfill/test/Date/prototype/equals/argument-wrong-type.js new file mode 100644 index 0000000000..8833d1e824 --- /dev/null +++ b/polyfill/test/Date/prototype/equals/argument-wrong-type.js @@ -0,0 +1,19 @@ +// 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.date.prototype.equals +features: [Symbol] +---*/ + +const instance = Temporal.Date.from({ year: 2000, month: 5, day: 2 }); + +assert.throws(TypeError, () => instance.equals(undefined), "undefined"); +assert.throws(TypeError, () => instance.equals(null), "null"); +assert.throws(TypeError, () => instance.equals(true), "true"); +assert.throws(TypeError, () => instance.equals(""), "empty string"); +assert.throws(TypeError, () => instance.equals(Symbol()), "symbol"); +assert.throws(TypeError, () => instance.equals(1), "1"); +assert.throws(TypeError, () => instance.equals({}), "plain object"); +assert.throws(TypeError, () => instance.equals(Temporal.Date), "Temporal.Date"); +assert.throws(TypeError, () => instance.equals(Temporal.Date.prototype), "Temporal.Date.prototype"); diff --git a/polyfill/test/Date/prototype/equals/branding.js b/polyfill/test/Date/prototype/equals/branding.js new file mode 100644 index 0000000000..e2b89ab08f --- /dev/null +++ b/polyfill/test/Date/prototype/equals/branding.js @@ -0,0 +1,21 @@ +// 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.date.prototype.equals +features: [Symbol] +---*/ + +const equals = Temporal.Date.prototype.equals; + +assert.sameValue(typeof equals, "function"); + +assert.throws(TypeError, () => equals.call(undefined), "undefined"); +assert.throws(TypeError, () => equals.call(null), "null"); +assert.throws(TypeError, () => equals.call(true), "true"); +assert.throws(TypeError, () => equals.call(""), "empty string"); +assert.throws(TypeError, () => equals.call(Symbol()), "symbol"); +assert.throws(TypeError, () => equals.call(1), "1"); +assert.throws(TypeError, () => equals.call({}), "plain object"); +assert.throws(TypeError, () => equals.call(Temporal.Date), "Temporal.Date"); +assert.throws(TypeError, () => equals.call(Temporal.Date.prototype), "Temporal.Date.prototype"); diff --git a/polyfill/test/Date/prototype/equals/prop-desc.js b/polyfill/test/Date/prototype/equals/prop-desc.js new file mode 100644 index 0000000000..ef75c74ada --- /dev/null +++ b/polyfill/test/Date/prototype/equals/prop-desc.js @@ -0,0 +1,18 @@ +// Copyright (C) 2020 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +includes: [propertyHelper.js] +---*/ + +assert.sameValue( + typeof Temporal.Date.prototype.equals, + "function", + "`typeof Date.prototype.equals` is `function`" +); + +verifyProperty(Temporal.Date.prototype, "equals", { + writable: true, + enumerable: false, + configurable: true, +}); diff --git a/polyfill/test/DateTime/prototype/equals/argument-wrong-type.js b/polyfill/test/DateTime/prototype/equals/argument-wrong-type.js new file mode 100644 index 0000000000..f92383d776 --- /dev/null +++ b/polyfill/test/DateTime/prototype/equals/argument-wrong-type.js @@ -0,0 +1,19 @@ +// 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.datetime.prototype.equals +features: [Symbol] +---*/ + +const instance = Temporal.DateTime.from({ year: 2000, month: 5, day: 2, minute: 34, second: 56, millisecond: 987, microsecond: 654, nanosecond: 321 }); + +assert.throws(TypeError, () => instance.equals(undefined), "undefined"); +assert.throws(TypeError, () => instance.equals(null), "null"); +assert.throws(TypeError, () => instance.equals(true), "true"); +assert.throws(TypeError, () => instance.equals(""), "empty string"); +assert.throws(TypeError, () => instance.equals(Symbol()), "symbol"); +assert.throws(TypeError, () => instance.equals(1), "1"); +assert.throws(TypeError, () => instance.equals({}), "plain object"); +assert.throws(TypeError, () => instance.equals(Temporal.DateTime), "Temporal.DateTime"); +assert.throws(TypeError, () => instance.equals(Temporal.DateTime.prototype), "Temporal.DateTime.prototype"); diff --git a/polyfill/test/DateTime/prototype/equals/branding.js b/polyfill/test/DateTime/prototype/equals/branding.js new file mode 100644 index 0000000000..3cffe7f0b1 --- /dev/null +++ b/polyfill/test/DateTime/prototype/equals/branding.js @@ -0,0 +1,21 @@ +// 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.datetime.prototype.equals +features: [Symbol] +---*/ + +const equals = Temporal.DateTime.prototype.equals; + +assert.sameValue(typeof equals, "function"); + +assert.throws(TypeError, () => equals.call(undefined), "undefined"); +assert.throws(TypeError, () => equals.call(null), "null"); +assert.throws(TypeError, () => equals.call(true), "true"); +assert.throws(TypeError, () => equals.call(""), "empty string"); +assert.throws(TypeError, () => equals.call(Symbol()), "symbol"); +assert.throws(TypeError, () => equals.call(1), "1"); +assert.throws(TypeError, () => equals.call({}), "plain object"); +assert.throws(TypeError, () => equals.call(Temporal.DateTime), "Temporal.DateTime"); +assert.throws(TypeError, () => equals.call(Temporal.DateTime.prototype), "Temporal.DateTime.prototype"); diff --git a/polyfill/test/DateTime/prototype/equals/prop-desc.js b/polyfill/test/DateTime/prototype/equals/prop-desc.js new file mode 100644 index 0000000000..055b60f3e2 --- /dev/null +++ b/polyfill/test/DateTime/prototype/equals/prop-desc.js @@ -0,0 +1,19 @@ +// Copyright (C) 2020 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +includes: [propertyHelper.js] +---*/ + +const { DateTime } = Temporal; +assert.sameValue( + typeof DateTime.prototype.equals, + "function", + "`typeof DateTime.prototype.equals` is `function`" +); + +verifyProperty(DateTime.prototype, "equals", { + writable: true, + enumerable: false, + configurable: true, +}); diff --git a/polyfill/test/MonthDay/prototype/equals/argument-wrong-type.js b/polyfill/test/MonthDay/prototype/equals/argument-wrong-type.js new file mode 100644 index 0000000000..697c21c9c0 --- /dev/null +++ b/polyfill/test/MonthDay/prototype/equals/argument-wrong-type.js @@ -0,0 +1,19 @@ +// 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.monthday.prototype.equals +features: [Symbol] +---*/ + +const instance = Temporal.MonthDay.from({ month: 5, day: 2 }); + +assert.throws(TypeError, () => instance.equals(undefined), "undefined"); +assert.throws(TypeError, () => instance.equals(null), "null"); +assert.throws(TypeError, () => instance.equals(true), "true"); +assert.throws(TypeError, () => instance.equals(""), "empty string"); +assert.throws(TypeError, () => instance.equals(Symbol()), "symbol"); +assert.throws(TypeError, () => instance.equals(1), "1"); +assert.throws(TypeError, () => instance.equals({}), "plain object"); +assert.throws(TypeError, () => instance.equals(Temporal.MonthDay), "Temporal.MonthDay"); +assert.throws(TypeError, () => instance.equals(Temporal.MonthDay.prototype), "Temporal.MonthDay.prototype"); diff --git a/polyfill/test/MonthDay/prototype/equals/branding.js b/polyfill/test/MonthDay/prototype/equals/branding.js new file mode 100644 index 0000000000..76b83eff2c --- /dev/null +++ b/polyfill/test/MonthDay/prototype/equals/branding.js @@ -0,0 +1,21 @@ +// 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.monthday.prototype.equals +features: [Symbol] +---*/ + +const equals = Temporal.MonthDay.prototype.equals; + +assert.sameValue(typeof equals, "function"); + +assert.throws(TypeError, () => equals.call(undefined), "undefined"); +assert.throws(TypeError, () => equals.call(null), "null"); +assert.throws(TypeError, () => equals.call(true), "true"); +assert.throws(TypeError, () => equals.call(""), "empty string"); +assert.throws(TypeError, () => equals.call(Symbol()), "symbol"); +assert.throws(TypeError, () => equals.call(1), "1"); +assert.throws(TypeError, () => equals.call({}), "plain object"); +assert.throws(TypeError, () => equals.call(Temporal.MonthDay), "Temporal.MonthDay"); +assert.throws(TypeError, () => equals.call(Temporal.MonthDay.prototype), "Temporal.MonthDay.prototype"); diff --git a/polyfill/test/MonthDay/prototype/equals/prop-desc.js b/polyfill/test/MonthDay/prototype/equals/prop-desc.js new file mode 100644 index 0000000000..81226b20dc --- /dev/null +++ b/polyfill/test/MonthDay/prototype/equals/prop-desc.js @@ -0,0 +1,19 @@ +// Copyright (C) 2020 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +includes: [propertyHelper.js] +---*/ + +const { MonthDay } = Temporal; +assert.sameValue( + typeof MonthDay.prototype.equals, + "function", + "`typeof MonthDay.prototype.equals` is `function`" +); + +verifyProperty(MonthDay.prototype, "equals", { + writable: true, + enumerable: false, + configurable: true, +}); diff --git a/polyfill/test/Time/prototype/equals/argument-wrong-type.js b/polyfill/test/Time/prototype/equals/argument-wrong-type.js new file mode 100644 index 0000000000..cf38e5589b --- /dev/null +++ b/polyfill/test/Time/prototype/equals/argument-wrong-type.js @@ -0,0 +1,19 @@ +// 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.time.prototype.equals +features: [Symbol] +---*/ + +const instance = Temporal.Time.from({ minute: 34, second: 56, millisecond: 987, microsecond: 654, nanosecond: 321 }); + +assert.throws(TypeError, () => instance.equals(undefined), "undefined"); +assert.throws(TypeError, () => instance.equals(null), "null"); +assert.throws(TypeError, () => instance.equals(true), "true"); +assert.throws(TypeError, () => instance.equals(""), "empty string"); +assert.throws(TypeError, () => instance.equals(Symbol()), "symbol"); +assert.throws(TypeError, () => instance.equals(1), "1"); +assert.throws(TypeError, () => instance.equals({}), "plain object"); +assert.throws(TypeError, () => instance.equals(Temporal.Time), "Temporal.Time"); +assert.throws(TypeError, () => instance.equals(Temporal.Time.prototype), "Temporal.Time.prototype"); diff --git a/polyfill/test/Time/prototype/equals/branding.js b/polyfill/test/Time/prototype/equals/branding.js new file mode 100644 index 0000000000..1d028af1b5 --- /dev/null +++ b/polyfill/test/Time/prototype/equals/branding.js @@ -0,0 +1,21 @@ +// 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.time.prototype.equals +features: [Symbol] +---*/ + +const equals = Temporal.Time.prototype.equals; + +assert.sameValue(typeof equals, "function"); + +assert.throws(TypeError, () => equals.call(undefined), "undefined"); +assert.throws(TypeError, () => equals.call(null), "null"); +assert.throws(TypeError, () => equals.call(true), "true"); +assert.throws(TypeError, () => equals.call(""), "empty string"); +assert.throws(TypeError, () => equals.call(Symbol()), "symbol"); +assert.throws(TypeError, () => equals.call(1), "1"); +assert.throws(TypeError, () => equals.call({}), "plain object"); +assert.throws(TypeError, () => equals.call(Temporal.Time), "Temporal.Time"); +assert.throws(TypeError, () => equals.call(Temporal.Time.prototype), "Temporal.Time.prototype"); diff --git a/polyfill/test/Time/prototype/equals/prop-desc.js b/polyfill/test/Time/prototype/equals/prop-desc.js new file mode 100644 index 0000000000..930380803f --- /dev/null +++ b/polyfill/test/Time/prototype/equals/prop-desc.js @@ -0,0 +1,19 @@ +// Copyright (C) 2020 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +includes: [propertyHelper.js] +---*/ + +const { Time } = Temporal; +assert.sameValue( + typeof Time.prototype.equals, + "function", + "`typeof Time.prototype.equals` is `function`" +); + +verifyProperty(Time.prototype, "equals", { + writable: true, + enumerable: false, + configurable: true, +}); diff --git a/polyfill/test/YearMonth/prototype/equals/argument-wrong-type.js b/polyfill/test/YearMonth/prototype/equals/argument-wrong-type.js new file mode 100644 index 0000000000..f58b0a40d9 --- /dev/null +++ b/polyfill/test/YearMonth/prototype/equals/argument-wrong-type.js @@ -0,0 +1,19 @@ +// 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.yearmonth.prototype.equals +features: [Symbol] +---*/ + +const instance = Temporal.YearMonth.from({ year: 2000, month: 5, day: 2 }); + +assert.throws(TypeError, () => instance.equals(undefined), "undefined"); +assert.throws(TypeError, () => instance.equals(null), "null"); +assert.throws(TypeError, () => instance.equals(true), "true"); +assert.throws(TypeError, () => instance.equals(""), "empty string"); +assert.throws(TypeError, () => instance.equals(Symbol()), "symbol"); +assert.throws(TypeError, () => instance.equals(1), "1"); +assert.throws(TypeError, () => instance.equals({}), "plain object"); +assert.throws(TypeError, () => instance.equals(Temporal.YearMonth), "Temporal.YearMonth"); +assert.throws(TypeError, () => instance.equals(Temporal.YearMonth.prototype), "Temporal.YearMonth.prototype"); diff --git a/polyfill/test/YearMonth/prototype/equals/branding.js b/polyfill/test/YearMonth/prototype/equals/branding.js new file mode 100644 index 0000000000..19f30c704d --- /dev/null +++ b/polyfill/test/YearMonth/prototype/equals/branding.js @@ -0,0 +1,21 @@ +// 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.yearmonth.prototype.equals +features: [Symbol] +---*/ + +const equals = Temporal.YearMonth.prototype.equals; + +assert.sameValue(typeof equals, "function"); + +assert.throws(TypeError, () => equals.call(undefined), "undefined"); +assert.throws(TypeError, () => equals.call(null), "null"); +assert.throws(TypeError, () => equals.call(true), "true"); +assert.throws(TypeError, () => equals.call(""), "empty string"); +assert.throws(TypeError, () => equals.call(Symbol()), "symbol"); +assert.throws(TypeError, () => equals.call(1), "1"); +assert.throws(TypeError, () => equals.call({}), "plain object"); +assert.throws(TypeError, () => equals.call(Temporal.YearMonth), "Temporal.YearMonth"); +assert.throws(TypeError, () => equals.call(Temporal.YearMonth.prototype), "Temporal.YearMonth.prototype"); diff --git a/polyfill/test/YearMonth/prototype/equals/prop-desc.js b/polyfill/test/YearMonth/prototype/equals/prop-desc.js new file mode 100644 index 0000000000..84d1e1e594 --- /dev/null +++ b/polyfill/test/YearMonth/prototype/equals/prop-desc.js @@ -0,0 +1,19 @@ +// Copyright (C) 2020 Igalia, S.L. All rights reserved. +// This code is governed by the BSD license found in the LICENSE file. + +/*--- +includes: [propertyHelper.js] +---*/ + +const { YearMonth } = Temporal; +assert.sameValue( + typeof YearMonth.prototype.equals, + "function", + "`typeof YearMonth.prototype.equals` is `function`" +); + +verifyProperty(YearMonth.prototype, "equals", { + writable: true, + enumerable: false, + configurable: true, +}); diff --git a/polyfill/test/absolute.mjs b/polyfill/test/absolute.mjs index d4e2871117..e333804184 100644 --- a/polyfill/test/absolute.mjs +++ b/polyfill/test/absolute.mjs @@ -22,6 +22,15 @@ describe('Absolute', () => { it('Absolute is a Function', () => { equal(typeof Absolute, 'function'); }); + it('Absolute has a prototype', () => { + assert(Absolute.prototype); + equal(typeof Absolute.prototype, 'object'); + }); + describe('Absolute.prototype', () => { + it('Absolute.prototype.equals is a Function', () => { + equal(typeof Absolute.prototype.equals, 'function'); + }); + }); it('Absolute.fromEpochSeconds is a Function', () => { equal(typeof Absolute.fromEpochSeconds, 'function'); }); @@ -345,8 +354,8 @@ describe('Absolute', () => { equal(`${one}`, '1969-12-15T12:23:45.678900434Z')); it(`(${abs}).plus({ days: 10, nanoseconds: 800 }) = ${two}`, () => equal(`${two}`, '1970-01-04T12:23:45.678902034Z')); - it(`(${two}).minus({ days: 20, nanoseconds: 1600 }) = ${one}`, () => equal(`${three}`, `${one}`)); - it(`(${one}).plus( days: 20, nanoseconds: 1600 }) = ${two}`, () => equal(`${four}`, `${two}`)); + it(`(${two}).minus({ days: 20, nanoseconds: 1600 }) = ${one}`, () => assert(three.equals(one))); + it(`(${one}).plus( days: 20, nanoseconds: 1600 }) = ${two}`, () => assert(four.equals(two))); }); it('abs.plus(durationObj)', () => { const later = abs.plus(Temporal.Duration.from('P10DT0.000000800S')); @@ -387,14 +396,27 @@ describe('Absolute', () => { throws(() => Absolute.compare({}, abs2), TypeError); }); }); + describe('Absolute.equals works', () => { + const abs1 = Absolute.from('1963-02-13T09:36:29.123456789Z'); + const abs2 = Absolute.from('1976-11-18T15:23:30.123456789Z'); + const abs3 = Absolute.from('1981-12-15T14:34:31.987654321Z'); + it('pre epoch equal', () => assert(abs1.equals(abs1))); + it('epoch equal', () => assert(abs2.equals(abs2))); + it('cross epoch unequal', () => assert(!abs1.equals(abs2))); + it('epoch unequal', () => assert(!abs2.equals(abs3))); + it("doesn't cast argument", () => { + throws(() => abs1.equals(abs1.getEpochNanoseconds()), TypeError); + throws(() => abs1.equals({}), TypeError); + }); + }); describe('Absolute.difference works', () => { const earlier = Absolute.from('1976-11-18T15:23:30.123456789Z'); const later = Absolute.from('2019-10-29T10:46:38.271986102Z'); const diff = earlier.difference(later); it(`(${earlier}).difference(${later}) == (${later}).difference(${earlier})`, () => equal(`${later.difference(earlier)}`, `${diff}`)); - it(`(${earlier}).plus(${diff}) == (${later})`, () => equal(`${earlier.plus(diff)}`, `${later}`)); - it(`(${later}).minus(${diff}) == (${earlier})`, () => equal(`${later.minus(diff)}`, `${earlier}`)); + it(`(${earlier}).plus(${diff}) == (${later})`, () => assert(earlier.plus(diff).equals(later))); + it(`(${later}).minus(${diff}) == (${earlier})`, () => assert(later.minus(diff).equals(earlier))); it("doesn't cast argument", () => { throws(() => earlier.difference(later.toString()), TypeError); throws(() => earlier.difference({}), TypeError); diff --git a/polyfill/test/date.mjs b/polyfill/test/date.mjs index dffd0e5f6e..ccb14d5f6e 100644 --- a/polyfill/test/date.mjs +++ b/polyfill/test/date.mjs @@ -57,6 +57,9 @@ describe('Date', () => { it('Date.prototype.difference is a Function', () => { equal(typeof Date.prototype.difference, 'function'); }); + it('Date.prototype.equals is a Function', () => { + equal(typeof Date.prototype.equals, 'function'); + }); it('Date.prototype.withTime is a Function', () => { equal(typeof Date.prototype.withTime, 'function'); }); @@ -107,7 +110,7 @@ describe('Date', () => { it(`Temporal.Date.from(${JSON.stringify(datetime)}) instanceof Temporal.date`, () => assert(Date.from(datetime) instanceof Date)); it(`Temporal.Date.from(${JSON.stringify(datetime)}) === (${fromed})`, () => - equal(`${Date.from(datetime)}`, `${fromed}`)); + assert(Date.from(datetime).equals(fromed))); }); describe('.with manipulation', () => { const original = new Date(1976, 11, 18); @@ -373,7 +376,7 @@ describe('Date', () => { it('Date.from({}) throws', () => throws(() => Date.from({}), TypeError)); it('Date.from(required prop undefined) throws', () => throws(() => Date.from({ year: undefined, month: 11, day: 18 }), TypeError)); - it('Date.from(number) is converted to string', () => equal(`${Date.from(19761118)}`, `${Date.from('19761118')}`)); + it('Date.from(number) is converted to string', () => Date.from(19761118).equals(Date.from('19761118'))); it('basic format', () => { equal(`${Date.from('19761118')}`, '1976-11-18'); equal(`${Date.from('+0019761118')}`, '1976-11-18'); @@ -426,6 +429,16 @@ describe('Date', () => { throws(() => Date.compare(d1, '2019-06-30'), TypeError); }); }); + describe('Date.equal works', () => { + const d1 = Date.from('1976-11-18'); + const d2 = Date.from('2019-06-30'); + it('equal', () => assert(d1.equals(d1))); + it('unequal', () => assert(!d1.equals(d2))); + it("doesn't cast argument", () => { + throws(() => d2.equals({ year: 1976, month: 11, day: 18 }), TypeError); + throws(() => d2.equals('1976-11-18'), TypeError); + }); + }); describe('Min/max range', () => { it('constructing from numbers', () => { throws(() => new Date(-271821, 4, 18), RangeError); diff --git a/polyfill/test/datemath.mjs b/polyfill/test/datemath.mjs index a2599e87b7..d6d437f877 100644 --- a/polyfill/test/datemath.mjs +++ b/polyfill/test/datemath.mjs @@ -12,7 +12,6 @@ import Pretty from '@pipobscure/demitasse-pretty'; const { reporter } = Pretty; import { strict as assert } from 'assert'; -const { equal } = assert; import * as Temporal from 'tc39-temporal'; @@ -71,10 +70,8 @@ function buildSub(one, two, largestUnits) { largestUnits.forEach((largestUnit) => { describe(`< ${one} : ${two} (${largestUnit})>`, () => { const dif = two.difference(one, { largestUnit }); - it(`(${one}).plus(${dif}) => ${two}`, () => - equal(`${one.plus(dif, { disambiguation: 'reject' })}`, `${two}`, `(${one}).plus(${dif}) => ${two}`)); - it(`(${two}).minus(${dif}) => ${one}`, () => - equal(`${two.minus(dif, { disambiguation: 'reject' })}`, `${one}`, `(${two}).minus(${dif}) => ${one}`)); + it(`(${one}).plus(${dif}) => ${two}`, () => assert(one.plus(dif, { disambiguation: 'reject' }).equals(two))); + it(`(${two}).minus(${dif}) => ${one}`, () => assert(two.minus(dif, { disambiguation: 'reject' }).equals(one))); }); }); } diff --git a/polyfill/test/datetime.mjs b/polyfill/test/datetime.mjs index 73745815e7..9f5f8f5d6d 100644 --- a/polyfill/test/datetime.mjs +++ b/polyfill/test/datetime.mjs @@ -75,6 +75,9 @@ describe('DateTime', () => { it('DateTime.prototype.difference is a Function', () => { equal(typeof DateTime.prototype.difference, 'function'); }); + it('DateTime.prototype.equals is a Function', () => { + equal(typeof DateTime.prototype.equals, 'function'); + }); it('DateTime.prototype.inTimeZone is a Function', () => { equal(typeof DateTime.prototype.inTimeZone, 'function'); }); @@ -269,6 +272,16 @@ describe('DateTime', () => { throws(() => DateTime.compare('2019-10-29T10:46:38.271986102', dt2), TypeError); }); }); + describe('DateTime.equals() works', () => { + const dt1 = DateTime.from('1976-11-18T15:23:30.123456789'); + const dt2 = DateTime.from('2019-10-29T10:46:38.271986102'); + it('equal', () => assert(dt1.equals(dt1))); + it('unequal', () => assert(!dt1.equals(dt2))); + it("doesn't cast argument", () => { + throws(() => dt2.equals({ year: 1976, month: 11, day: 18, hour: 15 }), TypeError); + throws(() => dt2.equals('1976-11-18T15:23:30.123456789'), TypeError); + }); + }); describe('date/time maths', () => { const earlier = DateTime.from('1976-11-18T15:23:30.123456789'); const later = DateTime.from('2019-10-29T10:46:38.271986102'); @@ -276,8 +289,8 @@ describe('DateTime', () => { const diff = earlier.difference(later, { largestUnit }); it(`(${earlier}).difference(${later}, ${largestUnit}) == (${later}).difference(${earlier}, ${largestUnit})`, () => equal(`${later.difference(earlier, { largestUnit })}`, `${diff}`)); - it(`(${earlier}).plus(${diff}) == (${later})`, () => equal(`${earlier.plus(diff)}`, `${later}`)); - it(`(${later}).minus(${diff}) == (${earlier})`, () => equal(`${later.minus(diff)}`, `${earlier}`)); + it(`(${earlier}).plus(${diff}) == (${later})`, () => earlier.plus(diff).equals(later)); + it(`(${later}).minus(${diff}) == (${earlier})`, () => later.minus(diff).equals(earlier)); }); }); describe('date/time maths: hours overflow', () => { @@ -376,7 +389,7 @@ describe('DateTime', () => { equal(`${DateTime.from('2016-12-31T23:59:60')}`, '2016-12-31T23:59:59'); }); it('DateTime.from(number) is converted to string', () => - equal(`${DateTime.from(19761118)}`, `${DateTime.from('19761118')}`)); + assert(DateTime.from(19761118).equals(DateTime.from('19761118')))); describe('Disambiguation', () => { const bad = { year: 2019, month: 1, day: 32 }; it('reject', () => throws(() => DateTime.from(bad, { disambiguation: 'reject' }), RangeError)); diff --git a/polyfill/test/monthday.mjs b/polyfill/test/monthday.mjs index 2f8dc0233f..b3751a4d53 100644 --- a/polyfill/test/monthday.mjs +++ b/polyfill/test/monthday.mjs @@ -20,6 +20,9 @@ describe('MonthDay', () => { equal(typeof MonthDay.prototype, 'object'); }); describe('MonthDay.prototype', () => { + it('MonthDay.prototype.equals is a Function', () => { + equal(typeof MonthDay.prototype.equals, 'function'); + }); it('MonthDay.prototype.getFields is a Function', () => { equal(typeof MonthDay.prototype.getFields, 'function'); }); @@ -46,7 +49,7 @@ describe('MonthDay', () => { it('MonthDay.from(required prop undefined) throws', () => throws(() => MonthDay.from({ month: undefined, day: 15 }), TypeError)); it('MonthDay.from(number) is converted to string', () => - equal(`${MonthDay.from(1201)}`, `${MonthDay.from('12-01')}`)); + assert(MonthDay.from(1201).equals(MonthDay.from('12-01')))); it('basic format', () => { equal(`${MonthDay.from('1118')}`, '11-18'); }); @@ -123,6 +126,16 @@ describe('MonthDay', () => { equal(`${md.with({ month: 999999 * 12 }, { disambiguation: 'balance' })}`, '12-01'); }); }); + describe('MonthDay.equals()', () => { + const md1 = MonthDay.from('01-22'); + const md2 = MonthDay.from('12-15'); + it('equal', () => assert(md1.equals(md1))); + it('unequal', () => assert(!md1.equals(md2))); + it("doesn't cast argument", () => { + throws(() => md1.equals('01-22'), TypeError); + throws(() => md1.equals({ month: 1, day: 22 }), TypeError); + }); + }); describe('MonthDay.withYear()', () => { const md = MonthDay.from('01-22'); it('takes a number argument', () => { @@ -153,11 +166,11 @@ describe('MonthDay', () => { }); it('as input to from()', () => { const md2 = MonthDay.from(fields); - equal(`${md1}`, `${md2}`); + assert(md1.equals(md2)); }); it('as input to with()', () => { const md2 = MonthDay.from('06-30').with(fields); - equal(`${md1}`, `${md2}`); + assert(md1.equals(md2)); }); }); }); diff --git a/polyfill/test/time.mjs b/polyfill/test/time.mjs index e0b09e735a..641845da71 100644 --- a/polyfill/test/time.mjs +++ b/polyfill/test/time.mjs @@ -57,6 +57,9 @@ describe('Time', () => { it('Time.prototype.difference is a Function', () => { equal(typeof Time.prototype.difference, 'function'); }); + it('Time.prototype.equals is a Function', () => { + equal(typeof Time.prototype.equals, 'function'); + }); it('Time.prototype.withDate is a Function', () => { equal(typeof Time.prototype.withDate, 'function'); }); @@ -321,6 +324,16 @@ describe('Time', () => { throws(() => Time.compare(t1, '16:34'), TypeError); }); }); + describe('time.equals() works', () => { + const t1 = Time.from('08:44:15.321'); + const t2 = Time.from('14:23:30.123'); + it('equal', () => assert(t1.equals(t1))); + it('unequal', () => assert(!t1.equals(t2))); + it("doesn't cast argument", () => { + throws(() => t1.equals('08:44:15.321'), TypeError); + throws(() => t1.equals({ hour: 8, minute: 44, second: 15, millisecond: 321 }), TypeError); + }); + }); describe('time.plus() works', () => { const time = new Time(15, 23, 30, 123, 456, 789); it(`(${time}).plus({ hours: 16 })`, () => { @@ -536,7 +549,7 @@ describe('Time', () => { it(`Temporal.Time.from(${JSON.stringify(datetime)}) instanceof Temporal.Time`, () => assert(Time.from(datetime) instanceof Time)); it(`Temporal.Time.from(${JSON.stringify(datetime)}) === ${fromed}`, () => - equal(`${Time.from(datetime)}`, `${fromed}`)); + assert(Time.from(datetime).equals(fromed))); const iso = '20:18:32'; it(`Temporal.Time.from("${iso}") === (${iso})`, () => equal(`${Time.from(iso)}`, iso)); diff --git a/polyfill/test/yearmonth.mjs b/polyfill/test/yearmonth.mjs index 8196a3b616..10e83a6052 100644 --- a/polyfill/test/yearmonth.mjs +++ b/polyfill/test/yearmonth.mjs @@ -23,6 +23,9 @@ describe('YearMonth', () => { it('YearMonth.prototype.difference is a Function', () => { equal(typeof YearMonth.prototype.difference, 'function'); }); + it('YearMonth.prototype.equals is a Function', () => { + equal(typeof YearMonth.prototype.equals, 'function'); + }); it('YearMonth.prototype.getFields is a Function', () => { equal(typeof YearMonth.prototype.getFields, 'function'); }); @@ -64,7 +67,7 @@ describe('YearMonth', () => { it('YearMonth.from(required prop undefined) throws', () => throws(() => YearMonth.from({ year: undefined, month: 6 }), TypeError)); it('YearMonth.from(number) is converted to string', () => - equal(`${YearMonth.from(201906)}`, `${YearMonth.from('201906')}`)); + assert(YearMonth.from(201906).equals(YearMonth.from('201906')))); it('basic format', () => { equal(`${YearMonth.from('197611')}`, '1976-11'); equal(`${YearMonth.from('+00197611')}`, '1976-11'); @@ -128,14 +131,24 @@ describe('YearMonth', () => { throws(() => YearMonth.compare(nov94, '2013-06'), TypeError); }); }); + describe('YearMonth.equals() works', () => { + const nov94 = YearMonth.from('1994-11'); + const jun13 = YearMonth.from('2013-06'); + it('equal', () => assert(nov94.equals(nov94))); + it('unequal', () => assert(!nov94.equals(jun13))); + it("doesn't cast argument", () => { + throws(() => nov94.equals({ year: 1994, month: 11 }), TypeError); + throws(() => nov94.equals('1994-11'), TypeError); + }); + }); describe('YearMonth.difference() works', () => { const nov94 = YearMonth.from('1994-11'); const jun13 = YearMonth.from('2013-06'); const diff = nov94.difference(jun13); it(`${nov94}.difference(${jun13}) == ${jun13}.difference(${nov94})`, () => equal(`${diff}`, `${jun13.difference(nov94)}`)); - it(`${nov94}.plus(${diff}) == ${jun13}`, () => equal(`${nov94.plus(diff)}`, `${jun13}`)); - it(`${jun13}.minus(${diff}) == ${nov94}`, () => equal(`${jun13.minus(diff)}`, `${nov94}`)); + it(`${nov94}.plus(${diff}) == ${jun13}`, () => nov94.plus(diff).equals(jun13)); + it(`${jun13}.minus(${diff}) == ${nov94}`, () => jun13.minus(diff).equals(nov94)); it("doesn't cast argument", () => { throws(() => nov94.difference({ year: 2013, month: 6 }), TypeError); throws(() => nov94.difference('2013-06'), TypeError); diff --git a/spec/absolute.html b/spec/absolute.html index 9e2710ef15..e491b5954a 100644 --- a/spec/absolute.html +++ b/spec/absolute.html @@ -298,6 +298,21 @@

Temporal.Absolute.prototype.difference ( _other_ [, _options_ ] )

+ +

Temporal.Absolute.prototype.equals ( _other_ )

+

+ The `equals` method takes one argument _other_. + The following steps are taken: +

+ + 1. Let _absolute_ be the *this* value. + 1. Perform ? RequireInternalSlot(_absolute_, [[InitializedTemporalAbsolute]]). + 1. Perform ? RequireInternalSlot(_other_, [[InitializedTemporalAbsolute]]). + 1. If _absolute_.[[Nanoseconds]] ≠ _other_.[[Nanoseconds]], return *false*. + 1. Return *true*. + +
+

Temporal.Absolute.prototype.toString ( [ _temporalTimeZoneLike_ ] )

diff --git a/spec/date.html b/spec/date.html index 0615556591..2499f0c864 100644 --- a/spec/date.html +++ b/spec/date.html @@ -360,6 +360,23 @@

Temporal.Date.prototype.difference ( _other_ [ , _options_ ] )

+ +

Temporal.Date.prototype.equals ( _other_ )

+

+ The `equals` method takes one argument _other_. + The following steps are taken: +

+ + 1. Let _temporalDate_ be the *this* value. + 1. Perform ? RequireInternalSlot(_temporalDate_, [[InitializedTemporalDate]]). + 1. Perform ? RequireInternalSlot(_other_, [[InitializedTemporalDate]]). + 1. If _temporalDate_.[[Year]] ≠ _other_.[[Year]], return *false*. + 1. If _temporalDate_.[[Month]] ≠ _other_.[[Month]], return *false*. + 1. If _temporalDate_.[[Day]] ≠ _other_.[[Day]], return *false*. + 1. Return *true*. + +
+

Temporal.Date.prototype.withTime ( _temporalTime_ )

diff --git a/spec/datetime.html b/spec/datetime.html index f580865ecc..e274c63dc4 100644 --- a/spec/datetime.html +++ b/spec/datetime.html @@ -447,6 +447,29 @@

Temporal.DateTime.prototype.difference ( _other_ [ , _options_ ] )

+ +

Temporal.DateTime.prototype.equals ( _other_ )

+

+ The `equals` method takes one argument _other_. + The following steps are taken: +

+ + 1. Let _dateTime_ be the *this* value. + 1. Perform ? RequireInternalSlot(_dateTime_, [[InitializedTemporalDateTime]]). + 1. Perform ? RequireInternalSlot(_other_, [[InitializedTemporalDateTime]]). + 1. If _dateTime_.[[Year]] ≠ _other_.[[Year]], return *false*. + 1. If _dateTime_.[[Month]] ≠ _other_.[[Month]], return *false*. + 1. If _dateTime_.[[Day]] ≠ _other_.[[Day]], return *false*. + 1. If _dateTime_.[[Hour]] ≠ _other_.[[Hour]], return *false*. + 1. If _dateTime_.[[Minute]] ≠ _other_.[[Minute]], return *false*. + 1. If _dateTime_.[[Second]] ≠ _other_.[[Second]], return *false*. + 1. If _dateTime_.[[Millisecond]] ≠ _other_.[[Millisecond]], return *false*. + 1. If _dateTime_.[[Microsecond]] ≠ _other_.[[Microsecond]], return *false*. + 1. If _dateTime_.[[Nanosecond]] ≠ _other_.[[Nanosecond]], return *false*. + 1. Return *true*. + +
+

Temporal.DateTime.prototype.toString ( )

diff --git a/spec/monthday.html b/spec/monthday.html index 8fc05d93fe..0914993e27 100644 --- a/spec/monthday.html +++ b/spec/monthday.html @@ -152,6 +152,22 @@

Temporal.MonthDay.prototype.with ( _temporalMonthDayLike_ [ , _options_ ] )< + +

Temporal.MonthDay.prototype.equals ( _other_ )

+

+ The `equals` method takes one argument _other_. + The following steps are taken: +

+ + 1. Let _monthDay_ be the *this* value. + 1. Perform ? RequireInternalSlot(_monthDay_, [[InitializedTemporalMonthDay]]). + 1. Perform ? RequireInternalSlot(_other_, [[InitializedTemporalMonthDay]]). + 1. If _monthDay_.[[Month]] ≠ _other_.[[Month]], return *false*. + 1. If _monthDay_.[[Day]] ≠ _other_.[[Day]], return *false*. + 1. Return *true*. + +
+

Temporal.MonthDay.prototype.toString ( )

diff --git a/spec/time.html b/spec/time.html index e7fdddccb9..6be33071c7 100644 --- a/spec/time.html +++ b/spec/time.html @@ -305,6 +305,26 @@

Temporal.Time.prototype.difference ( _other_ [ , _options_ ] )

+ +

Temporal.Time.prototype.equals ( _other_ )

+

+ The `equals` method takes one argument _other_. + The following steps are taken: +

+ + 1. Let _temporalTime_ be the *this* value. + 1. Perform ? RequireInternalSlot(_temporalTime_, [[InitializedTemporalTime]]). + 1. Perform ? RequireInternalSlot(_other_, [[InitializedTemporalTime]]). + 1. If _temporalTime_.[[Hour]] ≠ _other_.[[Hour]], return *false*. + 1. If _temporalTime_.[[Minute]] ≠ _other_.[[Minute]], return *false*. + 1. If _temporalTime_.[[Second]] ≠ _other_.[[Second]], return *false*. + 1. If _temporalTime_.[[Millisecond]] ≠ _other_.[[Millisecond]], return *false*. + 1. If _temporalTime_.[[Microsecond]] ≠ _other_.[[Microsecond]], return *false*. + 1. If _temporalTime_.[[Nanosecond]] ≠ _other_.[[Nanosecond]], return *false*. + 1. Return *true*. + +
+

Temporal.Time.prototype.withDate ( _temporalDate_ )

diff --git a/spec/yearmonth.html b/spec/yearmonth.html index fde79fc370..c4b1b9232b 100644 --- a/spec/yearmonth.html +++ b/spec/yearmonth.html @@ -271,6 +271,22 @@

Temporal.YearMonth.prototype.difference ( _other_ [ , _options_ ] )

+ +

Temporal.YearMonth.prototype.equals ( _other_ )

+

+ The `equals` method takes one argument _other_. + The following steps are taken: +

+ + 1. Let _yearMonth_ be the *this* value. + 1. Perform ? RequireInternalSlot(_yearMonth_, [[InitializedTemporalYearMonth]]). + 1. Perform ? RequireInternalSlot(_other_, [[InitializedTemporalYearMonth]]). + 1. If _yearMonth_.[[Year]] ≠ _other_.[[Year]], return *false*. + 1. If _yearMonth_.[[Month]] ≠ _other_.[[Month]], return *false*. + 1. Return *true*. + +
+

Temporal.YearMonth.prototype.toString ( )