From 01fdb3aee51795315805d6b793c5e5ff0051af53 Mon Sep 17 00:00:00 2001
From: Philip Chimento <pchimento@igalia.com>
Date: Fri, 10 May 2024 17:33:53 -0700
Subject: [PATCH] Normative: Remove TimeZone.p.equals

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>
---
 docs/timezone.md          | 68 ---------------------------------------
 docs/zoneddatetime.md     | 39 ++++++++++++++++++++++
 polyfill/index.d.ts       |  1 -
 polyfill/lib/timezone.mjs |  5 ---
 spec/timezone.html        | 13 --------
 5 files changed, 39 insertions(+), 87 deletions(-)

diff --git a/docs/timezone.md b/docs/timezone.md
index f0c02f0fa3..0ad41478a3 100644
--- a/docs/timezone.md
+++ b/docs/timezone.md
@@ -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:**
diff --git a/docs/zoneddatetime.md b/docs/zoneddatetime.md
index 2c3277b78b..1b3f184f70 100644
--- a/docs/zoneddatetime.md
+++ b/docs/zoneddatetime.md
@@ -1223,6 +1223,30 @@ 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
@@ -1230,6 +1254,21 @@ zdt1 = Temporal.ZonedDateTime.from('1995-12-07T03:24:30.000003500+01:00[Europe/P
 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
diff --git a/polyfill/index.d.ts b/polyfill/index.d.ts
index 99c3b77b35..6a4089a11b 100644
--- a/polyfill/index.d.ts
+++ b/polyfill/index.d.ts
@@ -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;
diff --git a/polyfill/lib/timezone.mjs b/polyfill/lib/timezone.mjs
index ca5b511716..9bfe832324 100644
--- a/polyfill/lib/timezone.mjs
+++ b/polyfill/lib/timezone.mjs
@@ -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);
diff --git a/spec/timezone.html b/spec/timezone.html
index 96ddff163d..fa0ad251a9 100644
--- a/spec/timezone.html
+++ b/spec/timezone.html
@@ -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>