JavaScript Intl API gives different results in Chr

2019-07-18 02:56发布

I am using JavaScript Intl API to detect the user's timezone in the browser:

Intl.DateTimeFormat().resolvedOptions().timeZone

While this API looks stable, I don't know what to do with the next. On my Windows 10 machine, the timezone is set to US Eastern Standard Time:

C:\> tzutil /g
US Eastern Standard Time

In Firefox and Edge the above JavaScript code results with "America/Indiana/Indianapolis", while Chrome returns just "America/Indianapolis".

Why this yields different results in different browsers? Is it a Chrome bug or should I transform the time zones somehow before processing them on the server?

On Ubuntu (which is my server's OS), if I list available time zones with timedatectl list-timezones, there is "America/Indiana/Indianapolis", but there is no "America/Indianapolis". Because of this issue I cannot accept Chrome's "America/Indianapolis" from the client, as I grab the "available time zones list" from the output of timedatectl list-timezones. Which behavior should I apply here?

Any help is appreciated. Thank you!

3条回答
劳资没心,怎么记你
2楼-- · 2019-07-18 03:45

Chrome, like many others, gets its time zone information through ICU, which in turn sources from CLDR, which in part sources from IANA.

There is a subtle difference between IANA and CLDR with regard to canonicalization.

  • IANA treats the preferred form of the time zone identifier as canonical. If the preferred form changes, they make the new one primary (a Zone entry) and move the old one to an alias (a Link entry).

  • CLDR treates the first form of the time zone identifier as canonical. That is, the first time it appeared in CLDR, it is locked in forever. If a new form ever appears, it is added as an alias in the /common/bcp47/timezone.xml file.

Taking your case of Indianapolis:

  • IANA Zone entry (reference here)

    Zone    America/Indiana/Indianapolis    ...
    
  • IANA Link entry (reference here)

    Link    America/Indiana/Indianapolis    America/Indianapolis
    
  • In CLDR, the primary zone is listed first in the "aliases" attribute, followed by other aliases. (reference here)

    <type name="usind" description="Indianapolis, United States" alias="America/Indianapolis America/Fort_Wayne America/Indiana/Indianapolis US/East-Indiana"/>
    

The same thing can be found with Asia/Calcutta vs. Asia/Kolkata and several other examples.

Additionally, be aware that the Windows time zone mappings also source from CLDR, in the /common/supplemental/windowsZones.xml file. You'll notice there that US Eastern Standard Time is mapped to America/Indianapolis. So the difference between browsers depends very much on which canonicalization rules are followed.

In the end, it doesn't really matter which alias is used. They point at the same data.

Also worth pointing out, that particular Windows zone should only be selected if you care about historical time changes in Indiana. If you are just in the US Eastern time zone, you should set your system to "Eastern Standard Time", rather than "US Eastern Standard Time". (Yes, those IDs are confusing...)

查看更多
唯我独甜
3楼-- · 2019-07-18 03:48

I'm not sure how/why each browser returns a different result (probably they read from different sources and/or it can be due to how each implements Intl.DateTimeFormat). But it doesn't matter, because both are the same timezone.

If you check this list, you'll see that America/Indianapolis links to America/Indiana/Indianapolis. Those names in the format Region/City are maintained by IANA and it's probably one of the best sources we have about timezone information.

IANA also keeps a backward file that maps those 2 names, with America/Indiana/Indianapolis being the most recent one.

So one alternative is to get a copy of the backward file and use it to map whatever name you receive to the respective new name, and also validate against your server's timezone list.

查看更多
疯言疯语
4楼-- · 2019-07-18 03:55

zone.tab is incomplete. Some time zones are represented as symbolic links:

$ find /usr/share/zoneinfo/America -name Indianapolis -exec file {} \;
/usr/share/zoneinfo/America/Indiana/Indianapolis: symbolic link to ../Indianapolis
/usr/share/zoneinfo/America/Indianapolis: timezone data, version 2, 7 gmt time flags, 7 std time flags, no leap seconds, 99 transition times, 7 abbreviation chars
查看更多
登录 后发表回答