Skip to content
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

typo in zone name Europe/Kyiv ? #2059

Open
tijujohn83 opened this issue Sep 12, 2022 · 6 comments
Open

typo in zone name Europe/Kyiv ? #2059

tijujohn83 opened this issue Sep 12, 2022 · 6 comments

Comments

@tijujohn83
Copy link

tijujohn83 commented Sep 12, 2022

'Europe/Kyiv' is not recognized but 'Europe/Kiev' is

example: following throws error as
dayjs('2018-01-02T00:00:00Z').tz('Europe/Kyiv')

image

Information

  • Day.js "version": "1.11.5"
@boyanstanchev
Copy link

boyanstanchev commented Oct 17, 2022

dayjs is using the Intl API, where the timezone is listed as 'Europe/Kiev'

You can check by yourself Intl.supportedValuesOf('timeZone')

chrome_lJULdLM0zX

@tukusejssirs
Copy link
Contributor

Just a note: Kiev is official English name of the city (derived from the Russian spelling), while Kyiv is transliteration of its Ukrainian name. Thus in English, Kyiv spelling is incorrect, although it is used by many people.

I think this issue should be closed, as until it is officially changed (by international English community and specifically by Intl API; see also KyivNotKiev campaign), there is not much dayjs can do.

/cc @iamkun

@justingrant
Copy link

ECMAScript libraries that accept time zone identifier string inputs generally accept both Europe/Kiev and Europe/Kyiv. This follows the behavior ofIntl.DateTimeFormat, as well as the coming-soon Temporal.TimeZone and Temporal.ZonedDateTime types. (Full disclosure: I'm part of the team that designed the Temporal API, and I did a lot of work on the time-zone-related parts of it.)

If you want to know more about why both spellings should be accepted, below is background info.

Time zone identifiers in ECMAScript are based on the IANA Time Zone Database, or "TZDB". The TZDB has a backwards compatibility mechanism where multiple names (called "Links" in TZDB) can map to the same canonical time zone (called "Zone" in TZDB). So it's surprising that an Intl-based library would not accept all aliases for a time zone.

Here's some code showing that Intl.DateTimeFormat accepts both.

// Chrome, Safari
new Intl.DateTimeFormat('en', { timeZone: 'Europe/Kiev' }).resolvedOptions().timeZone;
// => 'Europe/Kiev'
new Intl.DateTimeFormat('en', { timeZone: 'Europe/Kyiv' }).resolvedOptions().timeZone;
// => 'Europe/Kiev'

// Firefox
new Intl.DateTimeFormat('en', { timeZone: 'Europe/Kiev' }).resolvedOptions().timeZone;
// => 'Europe/Kyiv'
new Intl.DateTimeFormat('en', { timeZone: 'Europe/Kyiv' }).resolvedOptions().timeZone;
// => 'Europe/Kyiv'

You'll notice that Firefox behavior differs from Chrome and Safari. This is because Firefox is actually following the TZDB. Here's an excerpt from the latest TZDB showing that Europe/Kyiv is a Zone (it's the canonical identifier) while Europe/Kiev is a Link (not canonical). You can see the latest TZDB Zones and Links here: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones.

image

The reason why Chrome and Safari return Europe/Kiev as canonical is because they rely on an internationalization library called ICU4C, which in turn gets its list of time zone identifiers (including which is canonical) from a data store called CLDR. It's the policy of ICU and CLDR to never update the canonical alias of a time zone once it's ever been published. This behavior has gradually led to a stale set of canonical identifiers in Chrome and Safari. It's not just Europe/Kiev, but also Asia/Calcutta (should be Asia/Kolkata), Asia/Saigon (should be Asia/Ho_Chi_Minh), and 10 more outdated canonical identifiers.

Firefox avoids this problem by determining canonical IDs directly from TZDB. Of course, that's not a panacea either because TZDB has lately been aggressively merging unrelated time zones (like Atlantic/Reykjavik + Africa/Abidjan, or Europe/Oslo + Europe/Berlin) and Firefox wisely backs these out using build options in the MAKEFILE of TZDB.

If you think this divergence between browsers is a bad idea, well I do too! I recently started a TC39 proposal to try to help fix it. Feedback on this proposal is always welcome.

This is probably much more information than you wanted to know about time zone identifiers, but if you're reading a bug report on dayjs then you might be a time zone nerd like me. :-)

@vsukhostavskyi-lyft
Copy link

Hey @justingrant
Thanks for your work on this matter, do you have updates on your proposal by any chance?

@justingrant
Copy link

Yep. It took a long time to make it happen, but last year we added text in ECMA-402 (the JS i18n standard) that defines exactly how JS implementations should handle time zone IDs, including how to handle renames of existing IDs.

There's a lot of edge cases for obscure time zones, but here's a summary of the changes:

  1. JS engines will stop canonicalizing IDs that users provide, so if you give JS Europe/Kiev then you'll get Europe/Kiev back. Ditto for Europe/Kyiv. JS will normalize the letter case e.g. ASIA/tokyo => Asia/Tokyo but won't change the case-insensitive ID. This ensures that automated tests and other code won't be broken by future renames of IDs.
  2. When IDs are provided by JS (e.g. fetching the system's time zone ID), then only the canonical ID will be returned, e.g. Europe/Kyiv or Asia/Ho_Chi_Minh. This ensures consistent behavior for time zone picker UIs across browsers, and also ensures that a localized TZ picker will always include the system's current time zone.
  3. When renames happen in the future, JS engines should recognize the new name ASAP, but should wait 2 years before making the new name canonical. This gives time for other systems (e.g. servers running older Node versions) to catch up with the new IDs before JS programs send those IDs to those other systems.
  4. To determine if two time zones are aliases of each other, use code like this once Temporal is available:
function areTimeZonesEqual(id1, id2) {
  return new Temporal.ZonedDateTime(0n, id1).equals(new Temporal.ZonedDateTime(0n, id2))
}

I suspect that Firefox may already implement these changes, although @anba may know if there's anything that's not yet complete.

For V8 (Chrome, Node, Android) The last plan I heard was that they'll implement these changes after Temporal reaches Stage 4, which seems like it's on track to happen later this year. Although of course nothing is final until it happens! CLDR and ICU have already made the changes needed (see the new iana attribute in https://github.com/unicode-org/cldr/blob/main/common/bcp47/timezone.xml), so AFAIK all V8 needs to do is to start calling a different ICU API and we'll start seeing Europe/Kyiv.

I'm not sure about the JavaScriptCore (Safari, iOS/MacOS) implementation timeline.

@vsukhostavskyi-lyft Was that the info you were looking for?

@anba
Copy link

anba commented Jan 24, 2025

I suspect that Firefox may already implement these changes, although @anba may know if there's anything that's not yet complete.

https://github.com/tc39/proposal-canonical-tz is implemented for Temporal, but not for Intl.DateTimeFormat.prototype.resolvedOptions, because we don't yet know if this change is web-compatible (tc39/proposal-canonical-tz#2).

js> new Temporal.ZonedDateTime(0n, "europe/kiev").timeZoneId 
"Europe/Kiev"
js> new Temporal.ZonedDateTime(0n, "europe/kyiv").timeZoneId 
"Europe/Kyiv"
js> new Temporal.ZonedDateTime(0n, "europe/kiev").equals(new Temporal.ZonedDateTime(0n, "europe/kyiv")) 
true
js> new Intl.DateTimeFormat(undefined, {timeZone: "europe/kiev"}).resolvedOptions().timeZone 
"Europe/Kyiv"

And when setting the environment variable TZ=Europe/Kiev:

js> new Intl.DateTimeFormat().resolvedOptions().timeZone
"Europe/Kyiv"
js> Temporal.Now.zonedDateTimeISO().timeZoneId           
"Europe/Kyiv"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants