-
Notifications
You must be signed in to change notification settings - Fork 155
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
TimeZoneEquals should not fallback to comparison by id #2513
Comments
That seems like it would both block the optimization in #2482 for timezones, and also would mean that there's no reasonable way to equate two timezone objects that have the same behavior. It seems like a timezone object that has an ID but differing behavior just has a bug. |
No, because that optimization avoids object representations entirely when possible—the string representation is sufficient for built-in time zones, including for comparisons thereof.
That's kind of the point! Once you've got an object that can be mutated, there's no way to know which behavior is still the same. Consider code like const tz1 = Temporal.TimeZone.from('Asia/Tokyo');
const tz2 = Temporal.TimeZone.from('Asia/Tokyo');
const zdt0 = Temporal.Now.zonedDateTimeISO();
const zdt1 = zdt0.withTimeZone(tz1);
const zdt2 = zdt0.withTimeZone(tz2);
zdt1.equals(zdt2); // first comparison
Object.defineProperties(tz2, overrides); // post-hoc mutation of id and/or methods
zdt1.equals(zdt2); // second comparison
Sure, but at which level of abstraction and with how big a blast radius? I'm arguing that time zones that could behave differently from each other are never equal, which is not the case when they are the same string or the same object but is the case when they are distinct objects, and for which "id" is irrelevant. |
Note that the same issue affects calendars too: I think this issue comes down to what a
I think the former guarantee would be nice to have, but I also think that the latter guarantee is OK. Developers who want an absolute guarantee that object timezones and calendars will never mess things up should probably reject all usage of non-string calendars and timezones. Treating The reason that I'm OK with #2482 is that it won't break the ability for userland code to treat string IDs and built-in TimeZone objects polymorphically. Code can take a string ID, convert it to an object using But the change suggested in this issue would break this model by introducing significant functional differences. Examples: zdt1 = Temporal.Now.zonedDateTimeISO().withTimeZone(Temporal.TimeZone.from('Asia/Tokyo'));
zdt2 = zdt1.add({ hours: 48 }).withTimeZone(Temporal.TimeZone.from('Asia/Tokyo'));
zdt.equals(zdt2);
// => Expected: true. Actual: false
zdt.until(zdt2, { smallestUnit: 'day' });
// Expected: no exception. Actual: RangeError (comparing day lengths across time zones is ambiguous so not allowed) I agree with @gibson042 that ideally there'd be a way to differentiate ZDT instances that use two custom time zones that happened to pick the same string IDs. I'd support a change that enabled this without breaking the "objects work the same as strings" behavior of the current #2482 plan. But if the only solution to differentiating same-ID objects will break the current ability of built-in instances to be used whenever userland code uses string IDs, then I'd prefer to keep the currently-planned behavior and push the responsibilty onto custom timezone authors to use a distinct string ID for timezones that have distinct behavior. I think this aligns witih @ljharb's feedback above. If we had more time and resources, we could extend |
I'm fine with having this discussion separately from #2482/#1808, but I'm not in favour of considering it in scope of that change. We did already discuss this, in the context of both calendars and time zones, and the resolution was to explicitly leave it out of scope, and I'm not willing to hold up that issue to relitigate that. (Link to minutes; one of the conclusions is "If we want to change calendar equality semantics, discuss on a new issue.") So, assuming we agree to consider it separately from #2482/#1808, here's my opinion: I'm a strong -1 on this proposal. I agree with the reasons from Jordan and Justin. But most importantly I'm afraid of this (which is the reason I gave in the linked minutes): const calendar = Temporal.Calendar.from('gregory');
const date = Temporal.PlainDate.from({ year: 2023, month: 3, day: 2, calendar });
date.until('2023-03-21[u-ca=gregory]') Or this: const firstCalendar = Temporal.Calendar.from('gregory');
const firstDate = Temporal.PlainDate.from({ year: 2023, month: 3, day: 2, calendar: firstCalendar });
const secondCalendar = Temporal.Calendar.from('gregory');
const secondDate = Temporal.PlainDate.from({ year: 2023, month: 3, day: 21, calendar: secondCalendar });
firstDate.until(secondDate) What would you expect to happen in these code snippets? With this proposed change, they would both throw a RangeError, probably with a cryptic message like "can't compare dates in 'gregory' and 'gregory' calendars." Of course we as experts know that you should use strings for your builtin calendars, for performance, but that's not obvious to learners, and I'd find it too easy to end up with Temporal objects like the above which are non-obviously 'poisoned' so they're incompatible with each other. (In the status quo, there is no problem with the above snippets.) For the problem of calendar and time zone objects that have the same ID but different behaviour, I agree strongly with Jordan, that's a bug. I think it should be one of the invariants when creating a custom calendar or time zone that it must report a different ID if it has different behaviour, as Justin said above. |
I also agree strongly that distinct calendars and time zones with the same ID is a bug, and I'm very strongly against the platform masking such bugs (or worse, enabling malicious code to intentionally exploit them). I can live with allowing your |
Object equality does not guarantee equal behavior. A malicious time zone or calendar object can simply return different results from subsequent method calls. So if we're talking accidental, non-malicious bugs, then it's worth comparing two classes of those bugs:
I assume that (1) will be vastly more common, because custom timezones and calendars are advanced, somewhat-niche features, while built-in TimeZone and Calendar objects are common. Also, we've designed the entire API surface to mask the differences between strings and objects, so having If we have to allow the possibility of bugs, I'd prefer to limit bugs to more obscure cases in exchange for mainstream cases working as expected. |
I don't expect any use of Footnotes
|
Yeah, this one wasn't my favorite. It was a concession as a condition of getting to Stage 3. Proposal was going to be blocked otherwise, as we learned in a side meeting right before (or after?) the plenary where we asked for Stage 3. See #1431 for context. @ptomato may remember more details. I didn't particularly agree with the request (still don't!), but I also didn't disagree so strongly that it would be worth holding up Stage 3. If I remember correctly, I think the other champions felt likewise. Consensus sometimes has its downsides. BTW, the
The use case that immediately comes to mind for The case for including time zone in The case for including calendar in
We're generally in agreement that throwing exceptions for ambiguous cases is a good thing, but I admittedly didn't know how that applies here. Sorry for not following! Could you clarify how |
I considered something like that, but it felt contrived to the point of uselessness... such items should either correspond with events that have their own unique identifiers in case of simultaneity, or should otherwise have an actual representation beyond just "zoned timestamp". And even if that's not the case, being explicit about including calendar and/or time zone in matching logic seems superior to hiding it inside those aspects inside a loose-string-mapping
No, but to use your example of iterating over |
Meeting 2023-03-09 (forgot to record it before): We'll keep the existing behavior that ID equality is used to determine calendar equality and time zone equality. |
Raised in #2509 (comment) as commentary on a proposed change, but was observed in #2509 (comment) to be an existing issue.
TimeZoneEquals currently reports
true
when provided with distinct objects that have the same string value, but that behavior is problematic.Instead, distinct time zone objects should always be reported non-equal.
This may be in scope for #2482 .
The text was updated successfully, but these errors were encountered: