Skip to content

Commit

Permalink
Allow strings and property bags in equals() methods
Browse files Browse the repository at this point in the history
See: #592
  • Loading branch information
ptomato authored and Ms2ger committed Oct 21, 2020
1 parent 10a441b commit 3f21dd6
Show file tree
Hide file tree
Showing 31 changed files with 113 additions and 82 deletions.
6 changes: 4 additions & 2 deletions docs/date.md
Expand Up @@ -498,11 +498,11 @@ date.toDateTime(noon).difference(other.toDateTime(noon), { largestUnit: 'hours'
```
<!-- prettier-ignore-end -->

### date.**equals**(_other_: Temporal.Date) : boolean
### date.**equals**(_other_: Temporal.Date | object | string) : boolean

**Parameters:**

- `other` (`Temporal.Date`): Another date to compare.
- `other` (`Temporal.Date` or value convertible to one): Another date to compare.

**Returns:** `true` if `date` and `other` are equal, or `false` if not.

Expand All @@ -514,6 +514,8 @@ If you don't need to know the order in which the two dates occur, then this func

Note that this function will return `true` if the two dates are equal, even if they are expressed in different calendar systems.

If `other` is not a `Temporal.Date` object, then it will be converted to one as if it were passed to `Temporal.Date.from()`.

Example usage:

```javascript
Expand Down
4 changes: 3 additions & 1 deletion docs/datetime.md
Expand Up @@ -636,7 +636,7 @@ dt.round({ roundingIncrement: 30, smallestUnit: 'minute', roundingMode: 'floor'
```
<!-- prettier-ignore-end -->

### datetime.**equals**(_other_: Temporal.DateTime) : boolean
### datetime.**equals**(_other_: Temporal.DateTime | object | string) : boolean

**Parameters:**

Expand All @@ -652,6 +652,8 @@ If you don't need to know the order in which the two dates/times occur, then thi

Note that this function will return `true` if the two date/times are equal, even if they are expressed in different calendar systems.

If `other` is not a `Temporal.DateTime` object, then it will be converted to one as if it were passed to `Temporal.DateTime.from()`.

Example usage:

```javascript
Expand Down
6 changes: 4 additions & 2 deletions docs/instant.md
Expand Up @@ -546,11 +546,11 @@ instant.round({ roundingIncrement: 60, smallestUnit: 'minute', roundingMode: 'fl
```
<!-- prettier-ignore-end -->

### instant.**equals**(_other_: Temporal.Instant) : boolean
### instant.**equals**(_other_: Temporal.Instant | string) : boolean

**Parameters:**

- `other` (`Temporal.Instant`): Another exact time to compare.
- `other` (`Temporal.Instant` or value convertible to one): Another exact time to compare.

**Returns:** `true` if `instant` and `other` are equal, or `false` if not.

Expand All @@ -560,6 +560,8 @@ This function exists because it's not possible to compare using `instant == othe

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.Instant.compare`.

If `other` is not a `Temporal.Instant` object, then it will be converted to one as if it were passed to `Temporal.Instant.from()`.

Example usage:

```javascript
Expand Down
6 changes: 4 additions & 2 deletions docs/monthday.md
Expand Up @@ -156,10 +156,10 @@ md.with({ day: 31 }) // => 11-30
Temporal.MonthDay.from('02-01').with({ day: 31 }); // => 02-29
```

### monthDay.**equals**(_other_: Temporal.MonthDay) : boolean
### monthDay.**equals**(_other_: Temporal.MonthDay | object | string) : boolean

**Parameters:**
- `other` (`Temporal.MonthDay`): Another month-day to compare.
- `other` (`Temporal.MonthDay` or value convertible to one): Another month-day to compare.

**Returns:** `true` if `monthDay` and `other` are equal, or `false` if not.

Expand All @@ -169,6 +169,8 @@ This function exists because it's not possible to compare using `monthDay == oth

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.

If `other` is not a `Temporal.MonthDay` object, then it will be converted to one as if it were passed to `Temporal.MonthDay.from()`.

Example usage:
```javascript
dt1 = Temporal.DateTime.from('1995-12-07T03:24:30.000003500');
Expand Down
6 changes: 4 additions & 2 deletions docs/time.md
Expand Up @@ -367,11 +367,11 @@ time.round({ roundingIncrement: 30, smallestUnit: 'minute', roundingMode: 'ceil'
```
<!-- prettier-ignore-end -->

### time.**equals**(_other_: Temporal.Time) : boolean
### time.**equals**(_other_: Temporal.Time | object | string) : boolean

**Parameters:**

- `other` (`Temporal.Time`): Another time to compare.
- `other` (`Temporal.Time` or value convertible to one): Another time to compare.

**Returns:** `true` if `time` and `other` are equal, or `false` if not.

Expand All @@ -381,6 +381,8 @@ This function exists because it's not possible to compare using `time == other`

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`.

If `other` is not a `Temporal.Time` object, then it will be converted to one as if it were passed to `Temporal.Time.from()`.

Example usage:

```javascript
Expand Down
6 changes: 4 additions & 2 deletions docs/yearmonth.md
Expand Up @@ -365,17 +365,19 @@ other.difference(ym, { largestUnit: 'months' }) // => -P154M
ym.toDateOnDay(1).difference(other.toDateOnDay(1), { largestUnit: 'days' }); // => P4687D
```

### yearMonth.**equals**(_other_: Temporal.YearMonth) : boolean
### yearMonth.**equals**(_other_: Temporal.YearMonth | object | string) : boolean

**Parameters:**
- `other` (`Temporal.YearMonth`): Another month to compare.
- `other` (`Temporal.YearMonth` or value convertible to one): 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.

If `other` is not a `Temporal.YearMonth` object, then it will be converted to one as if it were passed to `Temporal.YearMonth.from()`.

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`.
Expand Down
21 changes: 12 additions & 9 deletions polyfill/index.d.ts
Expand Up @@ -302,7 +302,7 @@ export namespace Temporal {
readonly epochMilliseconds: number;
readonly epochMicroseconds: bigint;
readonly epochNanoseconds: bigint;
equals(other: Temporal.Instant): boolean;
equals(other: Temporal.Instant | string): boolean;
add(durationLike: Temporal.Duration | DurationLike | string): Temporal.Instant;
subtract(durationLike: Temporal.Duration | DurationLike | string): Temporal.Instant;
difference(
Expand Down Expand Up @@ -518,7 +518,7 @@ export namespace Temporal {
readonly daysInMonth: number;
readonly monthsInYear: number;
readonly isLeapYear: boolean;
equals(other: Temporal.Date): boolean;
equals(other: Temporal.Date | DateLike | string): boolean;
with(dateLike: DateLike | string, options?: AssignmentOptions): Temporal.Date;
withCalendar(calendar: CalendarProtocol | string): Temporal.Date;
add(durationLike: Temporal.Duration | DurationLike | string, options?: ArithmeticOptions): Temporal.Date;
Expand Down Expand Up @@ -633,7 +633,7 @@ export namespace Temporal {
readonly daysInMonth: number;
readonly monthsInYear: number;
readonly isLeapYear: boolean;
equals(other: Temporal.DateTime): boolean;
equals(other: Temporal.DateTime | DateTimeLike | string): boolean;
with(dateTimeLike: DateTimeLike | string, options?: AssignmentOptions): Temporal.DateTime;
withCalendar(calendar: CalendarProtocol | string): Temporal.DateTime;
add(durationLike: Temporal.Duration | DurationLike | string, options?: ArithmeticOptions): Temporal.DateTime;
Expand Down Expand Up @@ -717,7 +717,7 @@ export namespace Temporal {
readonly month: number;
readonly day: number;
readonly calendar: CalendarProtocol;
equals(other: Temporal.MonthDay): boolean;
equals(other: Temporal.MonthDay | MonthDayLike | string): boolean;
with(monthDayLike: MonthDayLike, options?: AssignmentOptions): Temporal.MonthDay;
toDateInYear(year: number | { era?: string | undefined; year: number }, options?: AssignmentOptions): Temporal.Date;
getFields(): MonthDayFields;
Expand Down Expand Up @@ -777,11 +777,14 @@ export namespace Temporal {
readonly millisecond: number;
readonly microsecond: number;
readonly nanosecond: number;
equals(other: Temporal.Time): boolean;
with(timeLike: Temporal.Time | TimeLike | string, options?: AssignmentOptions): Temporal.Time;
add(durationLike: Temporal.Time | Temporal.Duration | DurationLike, options?: ArithmeticOptions): Temporal.Time;
equals(other: Temporal.Time | TimeLike | string): boolean;
with(timeLike: Temporal.Time | TimeLike, options?: AssignmentOptions): Temporal.Time;
add(
durationLike: Temporal.Time | Temporal.Duration | DurationLike | string,
options?: ArithmeticOptions
): Temporal.Time;
subtract(
durationLike: Temporal.Time | Temporal.Duration | DurationLike,
durationLike: Temporal.Time | Temporal.Duration | DurationLike | string,
options?: ArithmeticOptions
): Temporal.Time;
difference(
Expand Down Expand Up @@ -905,7 +908,7 @@ export namespace Temporal {
readonly daysInYear: number;
readonly monthsInYear: number;
readonly isLeapYear: boolean;
equals(other: Temporal.YearMonth): boolean;
equals(other: Temporal.YearMonth | YearMonthLike | string): boolean;
with(yearMonthLike: YearMonthLike, options?: AssignmentOptions): Temporal.YearMonth;
add(durationLike: Temporal.Duration | DurationLike | string, options?: ArithmeticOptions): Temporal.YearMonth;
subtract(durationLike: Temporal.Duration | DurationLike | string, options?: ArithmeticOptions): Temporal.YearMonth;
Expand Down
2 changes: 1 addition & 1 deletion polyfill/lib/date.mjs
Expand Up @@ -227,7 +227,7 @@ export class Date {
}
equals(other) {
if (!ES.IsTemporalDate(this)) throw new TypeError('invalid receiver');
if (!ES.IsTemporalDate(other)) throw new TypeError('invalid Date object');
other = ES.ToTemporalDate(other, Date);
for (const slot of [ISO_YEAR, ISO_MONTH, ISO_DAY]) {
const val1 = GetSlot(this, slot);
const val2 = GetSlot(other, slot);
Expand Down
2 changes: 1 addition & 1 deletion polyfill/lib/datetime.mjs
Expand Up @@ -556,7 +556,7 @@ export class DateTime {
}
equals(other) {
if (!ES.IsTemporalDateTime(this)) throw new TypeError('invalid receiver');
if (!ES.IsTemporalDateTime(other)) throw new TypeError('invalid Date object');
other = ES.ToTemporalDateTime(other, DateTime);
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);
Expand Down
2 changes: 1 addition & 1 deletion polyfill/lib/instant.mjs
Expand Up @@ -213,7 +213,7 @@ export class Instant {
}
equals(other) {
if (!ES.IsTemporalInstant(this)) throw new TypeError('invalid receiver');
if (!ES.IsTemporalInstant(other)) throw new TypeError('invalid Instant object');
other = ES.ToTemporalInstant(other, Instant);
const one = GetSlot(this, EPOCHNANOSECONDS);
const two = GetSlot(other, EPOCHNANOSECONDS);
return bigInt(one).equals(two);
Expand Down
2 changes: 1 addition & 1 deletion polyfill/lib/monthday.mjs
Expand Up @@ -77,7 +77,7 @@ export class MonthDay {
}
equals(other) {
if (!ES.IsTemporalMonthDay(this)) throw new TypeError('invalid receiver');
if (!ES.IsTemporalMonthDay(other)) throw new TypeError('invalid MonthDay object');
other = ES.ToTemporalMonthDay(other, MonthDay);
for (const slot of [ISO_MONTH, ISO_DAY, ISO_YEAR]) {
const val1 = GetSlot(this, slot);
const val2 = GetSlot(other, slot);
Expand Down
2 changes: 1 addition & 1 deletion polyfill/lib/time.mjs
Expand Up @@ -357,7 +357,7 @@ export class Time {
}
equals(other) {
if (!ES.IsTemporalTime(this)) throw new TypeError('invalid receiver');
if (!ES.IsTemporalTime(other)) throw new TypeError('invalid Time object');
other = ES.ToTemporalTime(other, Time);
for (const slot of [HOUR, MINUTE, SECOND, MILLISECOND, MICROSECOND, NANOSECOND]) {
const val1 = GetSlot(this, slot);
const val2 = GetSlot(other, slot);
Expand Down
2 changes: 1 addition & 1 deletion polyfill/lib/yearmonth.mjs
Expand Up @@ -204,7 +204,7 @@ export class YearMonth {
}
equals(other) {
if (!ES.IsTemporalYearMonth(this)) throw new TypeError('invalid receiver');
if (!ES.IsTemporalYearMonth(other)) throw new TypeError('invalid YearMonth object');
other = ES.ToTemporalYearMonth(other, YearMonth);
for (const slot of [ISO_YEAR, ISO_MONTH, ISO_DAY]) {
const val1 = GetSlot(this, slot);
const val2 = GetSlot(other, slot);
Expand Down
10 changes: 5 additions & 5 deletions polyfill/test/Date/prototype/equals/argument-wrong-type.js
Expand Up @@ -8,12 +8,12 @@ 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(RangeError, () => instance.equals(undefined), "undefined");
assert.throws(RangeError, () => instance.equals(null), "null");
assert.throws(RangeError, () => instance.equals(true), "true");
assert.throws(RangeError, () => instance.equals(""), "empty string");
assert.throws(TypeError, () => instance.equals(Symbol()), "symbol");
assert.throws(TypeError, () => instance.equals(1), "1");
assert.throws(RangeError, () => 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");
10 changes: 5 additions & 5 deletions polyfill/test/DateTime/prototype/equals/argument-wrong-type.js
Expand Up @@ -8,12 +8,12 @@ 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(RangeError, () => instance.equals(undefined), "undefined");
assert.throws(RangeError, () => instance.equals(null), "null");
assert.throws(RangeError, () => instance.equals(true), "true");
assert.throws(RangeError, () => instance.equals(""), "empty string");
assert.throws(TypeError, () => instance.equals(Symbol()), "symbol");
assert.throws(TypeError, () => instance.equals(1), "1");
assert.throws(RangeError, () => 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");
14 changes: 7 additions & 7 deletions polyfill/test/Instant/prototype/equals/argument-wrong-type.js
Expand Up @@ -8,12 +8,12 @@ features: [Symbol]

const instance = Temporal.Instant.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(RangeError, () => instance.equals(undefined), "undefined");
assert.throws(RangeError, () => instance.equals(null), "null");
assert.throws(RangeError, () => instance.equals(true), "true");
assert.throws(RangeError, () => 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.Instant), "Temporal.Instant");
assert.throws(RangeError, () => instance.equals(1), "1");
assert.throws(RangeError, () => instance.equals({}), "plain object");
assert.throws(RangeError, () => instance.equals(Temporal.Instant), "Temporal.Instant");
assert.throws(TypeError, () => instance.equals(Temporal.Instant.prototype), "Temporal.Instant.prototype");
10 changes: 5 additions & 5 deletions polyfill/test/MonthDay/prototype/equals/argument-wrong-type.js
Expand Up @@ -8,12 +8,12 @@ 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(RangeError, () => instance.equals(undefined), "undefined");
assert.throws(RangeError, () => instance.equals(null), "null");
assert.throws(RangeError, () => instance.equals(true), "true");
assert.throws(RangeError, () => instance.equals(""), "empty string");
assert.throws(TypeError, () => instance.equals(Symbol()), "symbol");
assert.throws(TypeError, () => instance.equals(1), "1");
assert.throws(RangeError, () => 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");
10 changes: 5 additions & 5 deletions polyfill/test/Time/prototype/equals/argument-wrong-type.js
Expand Up @@ -8,12 +8,12 @@ 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(RangeError, () => instance.equals(undefined), "undefined");
assert.throws(RangeError, () => instance.equals(null), "null");
assert.throws(RangeError, () => instance.equals(true), "true");
assert.throws(RangeError, () => instance.equals(""), "empty string");
assert.throws(TypeError, () => instance.equals(Symbol()), "symbol");
assert.throws(TypeError, () => instance.equals(1), "1");
assert.throws(RangeError, () => 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");
10 changes: 5 additions & 5 deletions polyfill/test/YearMonth/prototype/equals/argument-wrong-type.js
Expand Up @@ -8,12 +8,12 @@ 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(RangeError, () => instance.equals(undefined), "undefined");
assert.throws(RangeError, () => instance.equals(null), "null");
assert.throws(RangeError, () => instance.equals(true), "true");
assert.throws(RangeError, () => instance.equals(""), "empty string");
assert.throws(TypeError, () => instance.equals(Symbol()), "symbol");
assert.throws(TypeError, () => instance.equals(1), "1");
assert.throws(RangeError, () => 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");
9 changes: 6 additions & 3 deletions polyfill/test/date.mjs
Expand Up @@ -706,9 +706,12 @@ describe('Date', () => {
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);
it('casts argument', () => {
assert(!d2.equals({ year: 1976, month: 11, day: 18 }));
assert(!d2.equals('1976-11-18'));
});
it('object must contain at least the required properties', () => {
throws(() => d2.equals({ year: 1976 }), TypeError);
});
});
describe("Comparison operators don't work", () => {
Expand Down

0 comments on commit 3f21dd6

Please sign in to comment.