Skip to content

Commit

Permalink
Normative: Remove TimeZone.p.equals
Browse files Browse the repository at this point in the history
The whole Temporal.TimeZone is going to be removed in the following
commit, but since this method is being replaced with an idiom that needs
documentation, I'm removing it in a separate commit for ease of review.

See: #2628

Co-Authored-By: Richard Gibson <richard.gibson@gmail.com>
  • Loading branch information
ptomato and gibson042 committed Jun 13, 2024
1 parent 2de101d commit 01fdb3a
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 87 deletions.
68 changes: 0 additions & 68 deletions docs/timezone.md
Original file line number Diff line number Diff line change
Expand Up @@ -219,74 +219,6 @@ When overriding `id`, `toString()` and `toJSON()` should also be overridden.

## Methods

### timeZone.**equals**(_other_: Temporal.TimeZone | object | string) : boolean

**Parameters:**

- `other` (`Temporal.TimeZone` object, object implementing the `Temporal.TimeZone` protocol, or a string time zone identifier): Another time zone to compare.

**Returns:** `true` if `timeZone` and `other` are equivalent, or `false` if not.

Compares two time zones for equivalence.
Equality is determined by the following algorithm:

- If `timeZone === other`, then the time zones are equivalent.
- Otherwise, `timeZone.id` is compared to `other` (or `other.id` if `other` is an object).
If any of the following conditions are true, then the time zones are equivalent:
- Both string identifiers are Zone or Link names in the [IANA Time Zone Database](https://www.iana.org/time-zones), and they resolve to the same Zone name.
This resolution is case-insensitive.
- Both string identifiers are custom time zone identifiers that are equal according to `===`.
This comparison is case-sensitive and does not normalize different Unicode characters.
- Both identifiers are numeric offset time zone identifiers like "+05:30", and they represent the same offset.
- Otherwise, the time zones are not equivalent.

Note that "resolve to the same Zone name" noted above is behavior that can vary between ECMAScript and other consumers of the IANA Time Zone Database.
ECMAScript implementations generally do not allow identifiers to be equivalent if they represent different <a href="https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2">ISO 3166-1 Alpha-2</a> country codes.
However, non-ECMAScript platforms may merge Zone names across country boundaries.
See [above](#variation-between-ecmascript-and-other-consumers-of-the-iana-time-zone-database) to learn more about this variation.

Time zones that resolve to different Zones in the IANA Time Zone Database are not equivalent, even if those Zones always use the same offsets.
Offset time zones and IANA time zones are also never equivalent.

Example usage:

<!-- prettier-ignore-start -->
```javascript
kolkata = Temporal.TimeZone.from('Asia/Kolkata');
kolkata.id; // => "Asia/Kolkata"
calcutta = Temporal.TimeZone.from('Asia/Calcutta');
calcutta.id; // => "Asia/Calcutta"
kolkata.equals(calcutta); // => true
kolkata.equals('Asia/Calcutta'); // => true
kolkata.equals('Asia/Colombo'); // => false

// IANA Time Zone Database identifiers are case insensitive
kolkata.equals('asia/calcutta'); // => true

// Offset time zones are never equivalent to named time zones
kolkata.equals('+05:30'); // => false
zeroOffset = Temporal.TimeZone.from('+00:00');
zeroOffset.equals('UTC'); // false

// For offset time zones, any valid format is accepted
zeroOffset.equals('+00:00'); // => true
zeroOffset.equals('+0000'); // => true
zeroOffset.equals('+00'); // => true

// Custom time zone identifiers are compared case-sensitively
class Custom1 extends Temporal.TimeZone {
constructor() { super('UTC'); }
get id() { return 'Moon/Cheese'; }
}
class Custom2 extends Temporal.TimeZone {
constructor() { super('UTC'); }
get id() { return 'Moon/CHEESE'; }
}
new Custom1().equals(new Custom1()); // => true
new Custom1().equals(new Custom2()); // => false
```
<!-- prettier-ignore-end -->

### timeZone.**getOffsetNanosecondsFor**(_instant_: Temporal.Instant | string) : number

**Parameters:**
Expand Down
39 changes: 39 additions & 0 deletions docs/zoneddatetime.md
Original file line number Diff line number Diff line change
Expand Up @@ -1223,13 +1223,52 @@ To ignore both time zones and calendars, compare the instants of both:
zdt.toInstant().equals(other.toInstant());
```

To compare time zone IDs directly, compare two ZonedDateTimes with the same instant and calendar:

```javascript
zdt.withTimeZone(id1).equals(zdt.withTimeZone(id2));
```

The time zones of _zonedDateTime_ and _other_ are considered equivalent by the following algorithm:

- If the time zone objects are the same object, then the time zones are equivalent.
- Otherwise, the IDs are compared.
If any of the following conditions are true, then the time zones are equivalent:
- Both string identifiers are Zone or Link names in the [IANA Time Zone Database](https://www.iana.org/time-zones), and they resolve to the same Zone name.
This resolution is case-insensitive.
- Both identifiers are numeric offset time zone identifiers like "+05:30", and they represent the same offset.
- Otherwise, the time zones are not equivalent.

Note that "resolve to the same Zone name" noted above is behavior that can vary between ECMAScript and other consumers of the IANA Time Zone Database.
ECMAScript implementations generally do not allow identifiers to be equivalent if they represent different <a href="https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2">ISO 3166-1 Alpha-2</a> country codes.
However, non-ECMAScript platforms may merge Zone names across country boundaries.
See [above](#variation-between-ecmascript-and-other-consumers-of-the-iana-time-zone-database) to learn more about this variation.

Time zones that resolve to different Zones in the IANA Time Zone Database are not equivalent, even if those Zones always use the same offsets.
Offset time zones and IANA time zones are also never equivalent.

Example usage:

```javascript
zdt1 = Temporal.ZonedDateTime.from('1995-12-07T03:24:30.000003500+01:00[Europe/Paris]');
zdt2 = Temporal.ZonedDateTime.from('1995-12-07T03:24:30.000003500+01:00[Europe/Brussels]');
zdt1.equals(zdt2); // => false (same offset but different time zones)
zdt1.equals(zdt1); // => true

// To compare time zone IDs, use withTimeZone() with each ID on the same
// ZonedDateTime instance, and use equals() to compare
kolkata = zdt1.withTimeZone('Asia/Kolkata');
kolkata.equals(zdt.withTimeZone('Asia/Calcutta')); // => true

// Offset time zones are never equivalent to named time zones
kolkata.equals(zdt.withTimeZone('+05:30')); // => false
zeroOffset = zdt1.withTimeZone('+00:00');
zeroOffset.equals(zdt1.withTimeZone('UTC')); // => false

// For offset time zones, any valid format is accepted
zeroOffset.equals(zdt1.withTimeZone('+00:00')); // => true
zeroOffset.equals(zdt1.withTimeZone('+0000')); // => true
zeroOffset.equals(zdt1.withTimeZone('+00')); // => true
```

### zonedDateTime.**toString**(_options_?: object) : string
Expand Down
1 change: 0 additions & 1 deletion polyfill/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1124,7 +1124,6 @@ export namespace Temporal {
static from(timeZone: TimeZoneLike): Temporal.TimeZone | TimeZoneProtocol;
constructor(timeZoneIdentifier: string);
readonly id: string;
equals(timeZone: TimeZoneLike): boolean;
getOffsetNanosecondsFor(instant: Temporal.Instant | string): number;
getOffsetStringFor(instant: Temporal.Instant | string): string;
getPlainDateTimeFor(instant: Temporal.Instant | string, calendar?: CalendarLike): Temporal.PlainDateTime;
Expand Down
5 changes: 0 additions & 5 deletions polyfill/lib/timezone.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,6 @@ export class TimeZone {
if (!ES.IsTemporalTimeZone(this)) throw new TypeError('invalid receiver');
return GetSlot(this, TIMEZONE_ID);
}
equals(other) {
if (!ES.IsTemporalTimeZone(this)) throw new TypeError('invalid receiver');
const timeZoneSlotValue = ES.ToTemporalTimeZoneSlotValue(other);
return ES.TimeZoneEquals(this, timeZoneSlotValue);
}
getOffsetNanosecondsFor(instant) {
if (!ES.IsTemporalTimeZone(this)) throw new TypeError('invalid receiver');
instant = ES.ToTemporalInstant(instant);
Expand Down
13 changes: 0 additions & 13 deletions spec/timezone.html
Original file line number Diff line number Diff line change
Expand Up @@ -106,19 +106,6 @@ <h1>get Temporal.TimeZone.prototype.id</h1>
</emu-alg>
</emu-clause>

<emu-clause id="sec-temporal.timezone.prototype.equals">
<h1>Temporal.TimeZone.prototype.equals ( _timeZoneLike_ )</h1>
<p>
This method performs the following steps when called:
</p>
<emu-alg>
1. Let _timeZone_ be the *this* value.
1. Perform ? RequireInternalSlot(_timeZone_, [[InitializedTemporalTimeZone]]).
1. Let _other_ be ? ToTemporalTimeZoneSlotValue(_timeZoneLike_).
1. Return ? TimeZoneEquals(_timeZone_, _other_).
</emu-alg>
</emu-clause>

<emu-clause id="sec-temporal.timezone.prototype.getoffsetnanosecondsfor">
<h1>Temporal.TimeZone.prototype.getOffsetNanosecondsFor ( _instant_ )</h1>
<p>
Expand Down

0 comments on commit 01fdb3a

Please sign in to comment.