Closed sffc closed 1 year ago
Should we perhaps focus this proposal on case 1?
Is your concern that we shouldn't wait for getting the full proposal to Stage 4 in order to make progress on (1)? Or that you think that (2) is unnecessary?
If the former, then I think we're on the same page. Our intent is to treat each of the 6 tasks in this proposal as independent things that can move forward in parallel. We don't need to wait to make progress on any of them. In particular, Steps 1-4 can be handled outside of the proposal stages. I expect to have an editorial PR for steps 1-2 ready for review later this week. And step 3 is not a spec change at all. Step 4 can be split out into a separate normative PR that probably doesn't need the proposal process, and honestly there's no urgency to 4 after we fix Step 3.
If the latter, then here's my case for why the API changes are needed. There two core problems to solve:
The hope is that if we can fix (b), then fixing (a) becomes a lot less painful for developers. So IMO it makes sense to try to tackle them in parallel so that fixing (a) causes less breakage across the ecosystem. Especially as Temporal starts to be used because Temporal makes canonicalization 100x+ more visible than today to userland developers.
I guess we could split it up into two different proposals: one to solve (a) above and the other to solve (b), but honestly (a) doesn't really need a proposal at all. It'd just be a consensus-needed normative PR. So the main reason to make this a proposal is to make API changes to solve (b).
What do you think?
What I mean is that one possible outcome of this proposal is that we specify to not canonicalize time zone IDs that come from user input, but that all time zone IDs that come from the standard library (via DefaultTimeZone or supportedValuesOf) should be in some particular canonical form.
I think I agree?
we specify to not canonicalize time zone IDs that come from user input
That's Task 5 in this proposal. If we decide to do this globally (including in resolvedOptions().timeZone
) then this might even be an editorial change (or at most a consensus normative PR) that could be split out from the proposal, because canonicalization is already implementation-defined. That would leave only the new TimeZone.p.equals
in Task 6 that would require going all the way to Stage 4.
all time zone IDs that come from the standard library (via DefaultTimeZone or supportedValuesOf) should be in some particular canonical form.
Yep, absolutely. This is Task 4. I expect that this can also be split out into a separate normative PR that could be a consensus PR that shouldn't need the whole Stage 1 - Stage 4 proposal process.
Is above what you had in mind? Sorry for so many questions, I'm intuiting that you have a strategic/process reason for this issue, and I suspect I will agree with you, but I'm trying to figure out what that reason is. :-)
IDs that come from the standard library (via DefaultTimeZone or supportedValuesOf) should be in some particular canonical form.
After thinking about this a bit more: is it necessary to canonicalize DefaultTimeZone? If I were Québécois and I decided to set my computer's time zone ID to America/Montreal, then does ECMAScript need to override that user's choice to America/Toronto? Seems like not canonicalizing there might prevent future geopolitical complaints because whatever your computer is set to is what your web apps return. Obviously this just defers the canonicalization choice to the OS, but maybe that's better than having ECMAScript decide?
On the other hand, for supportedValuesOf
an important use case is to enable a UI dropdown time zone chooser where for example, the set of Europe/Kiev and Europe/Kyiv only has one UI dropdown item, regardless of which one is canonical. So this API needs a way to pick one ID per group of IDs where TimeZoneEquals
returns true
, and so only returning canonical IDs seems appropriate there.
Yeah America/Montreal should stay but Europe/Kiev should be changed I think (in DefaultTimeZone).
Yeah America/Montreal should stay but Europe/Kiev should be changed I think (in DefaultTimeZone).
I'm not sure there's a good way to tell the difference between those two cases in the TZDB data. America/Montreal has been removed from zone.tab, and that file is the best way AFAICT for us to know which zones should be considered canonical in ECMAScript. It's how we can back out the undesirable merges like Reykjavik=>Abidjan. But if an identifier isn't in zone.tab, I'm not aware of any other place in TZDB that can tell us "this is a rename or deprecation" vs. "this is a real zone that's been merged into another one". We could of course use our own (or CLDR's) judgment to tell the difference, but I assumed that we don't want to get into that because it could be politically charged?
But feasibility aside, my first question is whether it's required to tell the difference. The operating system is determining the input to DefaultTimeZone. What's the benefit of overriding what the OS is telling us to do?
I had thought Montreal was a Merge to Toronto but you say it's only a Link?
Let's just state that the objective is that DefaultTimeZone is an entry of supportedValuesOf.
I had thought Montreal was a Merge to Toronto but you say it's only a Link?
There is no clear way in TZDB to distinguish between those cases. TZDB just knows about Zones and Links. "Merge" is a subjective thing, not a concept that TZDB explicitly supports. That said, we can infer most merges (especially the most problematic ones which are across country boundaries) via presence in zone.tab. If an identifier is in that file, then the appropriate TZDB build options which I think are PACKRATDATA=backzone PACKRATLIST=zone.tab
will convert all the Links in zone.tab into Zones in the resulting TZDB data files.
But Montreal was removed from zone.tab so I'm not sure how we'd differentiate it from a case like Kiev without special-casing somewhere (e.g. CLDR) that clarifies the difference.
BTW, other than the problematic 13 names (Calcutta, Saigon, Kiev, etc.) CLDR somewhat accidentally has adopted a similar solution to PACKRATDATA=backzone PACKRATLIST=zone.tab
because CLDR doesn't respect any renaming of canonical identifiers. Not saying the results are identical, but they're pretty close aside from those 13.
Let's just state that the objective is that DefaultTimeZone is an entry of supportedValuesOf.
It kinda depends. If we decide (and clearly document) that comparing time zone identifiers using ===
is unsupported and instead developers must use Temporal.TimeZone.p.equals
, then we may not need a "DefaultTimeZone is an entry of supportedValuesOf" invariant.
It's a tradeoff. If we canonicalize DefaultTimeZone, then we're exposed to user complaints that we're not matching their OS choices, and we increase the chance that upgrading a browser or Node will cause existing code to change behavior. On the other hand, if we don't canonicalize DefaultTimeZone, then users who don't use equals
can run into unexpected behavior, (e.g. a time zone dropdown with nothing selected), and we increase the chance that OS updates will cause existing code to change behavior.
I don't have an opinion yet about which way is the right way to go, but I think both are valid options to carefully consider the pros and cons of.
One other case to consider: what happens if the OS is updated before an ECMAScript engine is? Then the OS can report a particular IANA identifier that ECMAScript doesn't recognize. This is kinda off-topic to this issue but it came to mind while I was typing the comment above.
Not sure there's an easy solution to that, though, other than ensuring that ECMAScript implementations' TZDB is updated frequently instead of, for example, hardcoded into 2-year-old Node versions.
I guess right now I see it as the engine's problem to make sure any canonicalization invariants of DefaultTimeZone are upheld. JS user code is shielded from the actual origin of DefaultTimeZone. I think it would be really weird and unexpected for DefaultTimeZone to not be a "supported time zone" as defined by Intl.supportedValuesOf.
BTW, @anba just shared (in #11) two bug reports that may be relevant to this issue. In both cases, the OP is complaining that APIs downstream from DefaultTimeZone
will override the OS's time zone identifier setting.
WebKit 218542: Incorrect timezone returned for Buenos Aires Firefox 1796393: Javascript returns problematic timezone, breaking sites
Avoiding problems like this would I think be the main argument in favor of returning the OS's ID in DefaultTimeZone
.
JS user code is shielded from the actual origin of DefaultTimeZone. I think it would be really weird and unexpected for DefaultTimeZone to not be a "supported time zone" as defined by Intl.supportedValuesOf.
On the other hand, this is a good argument in favor of not using the OS's ID.
I guess a third option would be to change the canonicalization algorithm so that the OS's IANA ID is always guaranteed to be canonical. Then Intl.supportedValuesOf
and DefaultTimeZone would both include the OS's IANA ID, *and* we'd avoid complaints like the ones above. This third solution comes with its own problems, though:
Intl.supportedValuesOf
output would vary between different installs of the same browser versionNot sure if these issues are better or worse than the problems with the other two solutions above. What do you think?
BTW, @anba just shared (in #11) two bug reports that may be relevant to this issue. In both cases, the OP is complaining that APIs downstream from
DefaultTimeZone
will override the OS's time zone identifier setting.Firefox 1796393: Javascript returns problematic timezone, breaking sites
This is actually either:
It can't be an OS issue, because according to the bug report, the user is on Linux, which means "America/Nuuk" is the OS time zone. Linux typically uses IANA data and not CLDR data. For example when I change the time zone on Ubuntu via the time zone picker UI, where the time zone is selected based on the point you click on the map, selecting Greenland will set the time zone to "America/Nuuk":
ls -l /etc/localtime
lrwxrwxrwx 1 root root 32 Apr 2 23:52 /etc/localtime -> /usr/share/zoneinfo/America/Nuuk
Good point @anba about that case, I didn't read carefully enough. Only one of those bugs (WebKit 218542: Incorrect timezone returned for Buenos Aires) is actually about ECMAScript ignoring the OS's time zone ID setting.
But I realized that Firefox 1796393: Javascript returns problematic timezone, breaking sites might also be a case where allowing the OS's TZID setting to be reflected in ECMAScript could be useful. This user is complaining because Firefox breaks a website he needs for work. But if that user was able to set his OS to America/Godthab
and if ECMAScript returned that same ID (without canonicalizing) in DefaultTimeZone and supportedValuesOf
, then that user (or his IT department, for corporate users) would have a straightforward workaround for users who are dealing with out-of-date servers that don't yet recognize the current IANA canonical ID.
There are downsides to such a solution so I'm not sure whether I'm in favor of it or not, but I admit I do like the idea of giving users flexibility to work around problems like this.
Somewhat related to this issue: current non-Firefox ECMAScript engines don't guarantee that DefaultTimeZone is present in the output of Intl.supportedValuesOf("timeZone")
. See https://github.com/tc39/ecma402/issues/778.
This proposal is approaching Stage 3, and as a result of the discussion above and in TG2, this proposal is not planning to change any behavior of SystemTimeZoneIdentifier nor AvailableCanonicalTimeZones, because it's not clear that changes to those APIs would achieve TG2 consensus. (Even if we wanted to change them, which is also not clear.)
So I think we can close this issue now.
There are still problems (as noted above) with these APIs not outputting complete results and being inconsistent across implementations, as noted above. But those issues will have to be solved in a later proposal, or outside the ECMAScript spec (e.g. in CLDR or ICU).
There are two places time zone IDs can originate:
Should we perhaps focus this proposal on case 1? There are I think only really two places where time zone strings originate: