-
Notifications
You must be signed in to change notification settings - Fork 158
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
size-suggestion: Remove Temporal.TimeZone
class and protocol
#2853
Comments
TimeZone
type and protocolTemporal.TimeZone
type and protocol
Temporal.TimeZone
type and protocolTemporal.TimeZone
class and protocol
I wonder if this is a good example, because custom time zones (or custom calendars) don't work well with |
I wanted to capture on this thread one thing that custom time zones allow, which I forgot about: time zones with constant sub-minute offsets, like UTC+00:00:30. Note that there are still IANA time zones that used sub-minute UTC offsets after 1970, such as Africa/Monrovia. These are unaffected and continue to work. Custom time zones with constant sub-minute offsets were used in a couple places in test262 tests, mainly to test the same logic that would be used for zones like Africa/Monrovia, without requiring an IANA DB. I doubt they are much used in real life. If they were really needed, we could consider going back to sub-minute offset strings: e.g., |
Meeting 2024-05-23: At the upcoming June 2024 TC39 plenary meeting, we'll propose removing the Temporal.TimeZone class and protocol, for the following reasons:
To save one more function, the TimeZone.p.getNextTransition/getPreviousTransition methods are proposed to be merged into a single prototype method on Temporal.ZonedDateTime. Follow #2850 for details about that merger. |
So, with the issue's proposed changes, how do i identify the timezone of all the kinds of Temporal instances? How would I transform between a timezone ID, a UTC offset, the IANA name vs alternative names (in particular, the name |
This change would remove the ability for custom userland time zones, but it would make no changes to how built-in time zones (either named or offset) are handled in Temporal, in Intl, or by Date. Before and after the change in this issue, if you want to know the timezone of a
Today there's no "transformation" between time zones. An offset time zone has an ID that looks like an offset, and a named time zone has an ID that's a name, e.g. "UTC" or "Europe/Paris". And
By "the name If the responses above don't address your concern, could you clarify what you're wondering about? |
What I mean is, with a TimeZone object, there's an obvious single place to add future convenience methods to provide mappings to a given built-in timezone. Without one, it'd require adding a getter to each Temporal type, for each convenience method. Given size concerns, that seems like making this reduction now would effectively prevent any enhancement in the future. |
If there's ever a need to have extensive methods around time zones, we can revisit adding |
It's not clear to me how that would ever be possible - if "size" considerations block it now, they'd block it forever, and without the objects existing initially, how could it be possible to add in a nonbreaking way? |
To clarify: there's only one Temporal type with a time zone: And in 5+ years of working on Temporal we haven't found a justification for another Temporal type with a time zone. (In theory one could create a time+timezone or a date+timezone type, but the delta of value for those have never come close to justifying adding those types to the language.) So personally I'm not too worried about future compatibility here, because if something is judged to be important enough to be on TimeZone then it would likely be judged important enough to add to ZonedDateTime, or to add a TimeZone type again. |
IIUC the size limitations are because of current memory limits for certain devices. Smaller devices will likely gain more memory in the future, so adding a few kilobytes here and there won't matter that much anymore. |
@ljharb I'd like to understand your use cases better, I'm not sure what you mean by mappings. Here's what I would guess might help you: To get the time zone ID of a There isn't a one-to-one mapping between time zone ID and UTC offset. To map to a UTC offset you need a pair of time zone ID and exact time. You can get the UTC offset from Mapping IANA names to alternative time zone names has never been supported by Temporal even with |
ok, so, if i have a time zone ID, and nothing else, how do i get to that localized time zone name? If i have that localized time zone name from a Date object (and whatever else that Date object needs to provide), how can i get a time zone ID? |
The problem you'll run into is that the localized name (at least in some locales and some time zones) depends on the date chosen, e.g. "Eastern Standard Time" vs. "Eastern Daylight Time". I believe that this is why the DisplayNames V1 proposal didn't include time zone names, but you'd have to ask the champions of that proposal to know for sure. I believe (not 100% sure) that the In the meantime, here's how to get (what I think is?) the date-neutral time zone name: function getLocalizedTimeZoneName(locale, timeZone) {
const formatter = new Intl.DateTimeFormat(locale, { timeZoneName: 'longGeneric', timeZone });
const parts = formatter.formatToParts(new Date());
const timeZoneName = parts.find(part => part.type === 'timeZoneName');
return timeZoneName?.value;
}
getLocalizedTimeZoneName('en', 'America/Denver');
// => 'Mountain Time'
getLocalizedTimeZoneName('en', 'Asia/Tokyo');
// => 'Japan Standard Time'
Well, If what you're asking is how to take a localized date string that's been output on some computer and to parse that string into a time zone ID on some other computer, well I don't think that this is (or should be!) a supported use case. Localization is a one-way street. |
In general, I'm hoping to be able to treat a timezone as a first-class, reified thing, that i can extract from a Date or a relevant Temporal type, associate with an unzoned Temporal type to produce a zoned one, etc. The class and protocol seemed like the proper way to do that, and forcing all of that to be stringly typed doesn't seem like an improvement to me. |
The only correct, unambiguous localized representation of a time zone in CLDR is the exemplar city format, such as "New York Time". This solves ambiguities such as "Phoenix Time" and "Denver Time" being different, despite both being called "Mountain Time". We don't have that format currently exposed in Intl because it requires a lot of data (in the worst case, translations of 600 entities in each locale) and it is less popular when formatting a zoned datetime. However, it is the format that should back a DisplayNames impl if someone wanted to make such a proposal. |
Well, you can never extract a time zone from a Date because a Date doesn't have a time zone.
I don't think anyone is saying that removing 1/3 of Temporal surface area (from this issue plus all the others) is necessarily an improvement across the board (although some folks may suggest that some of the removals make things better). But our goal at this point is to make Temporal shippable by implementers who are concerned that Temporal as-is is too big and too complex. Cutting custom time zones provides >15% of the savings, which is considerable. And I'd much, much rather see us cut custom time zones instead of 15+ other functions in Temporal that have much more value for users. Especially given that we now understand that custom time zones can be implemented declaratively with no user code, and based on a standardized JSON format like JSCalendar. It seems reasonable IMO to drop the class and protocol from V1 and implement a better, declarative, standards-based custom time zone in a follow-up. It would be good to discuss as part of that follow-up proposal whether a dedicated TimeZone class makes sense to bring back.
Well, implementers demanded that we switch from objects to strings for performance reasons, so you may need to convince V8 and SpiderMonkey and JSC more than you need to convince me! 😄 |
@justingrant i can extract the local timezone from Date with |
That's not a time zone id, though. It's just a localised time zone name. js> console.log((new Date().toString()).match(/ \((.*)\)$/)[1])
Mitteleuropäische Sommerzeit And the same output when starting the js-shell with js> console.log((new Date().toString()).match(/ \((.*)\)$/)[1])
Mitteleuropäische Sommerzeit |
Not a solution, but it might be helpful to expose the TZDB version number/ID that is being used. |
That'd certainly be helpful if the host environment could expose it out-of-band, but hosts aren't required to use any version of the TZDB as long as they don't claim to be "time zone aware". |
This is a very large change, as it not only removes Temporal.Calendar and Temporal.TimeZone, but also tries to eliminate any extra complexity due to no longer having to deal with user code calls for calendar and time zone calculations. Some of the things that are removed or simplified include: - No more Calendar Method Records and Time Zone Method Records - In many places, no need to pass around the user's original options bag - In many places, no need to pass around the user's original PlainDate or Instant; use epoch nanoseconds, ISO Date Records, and ISO Date-Time Records instead - No more copying the own properties of options bags - Most of the calendar and time zone operations are now infallible - The set of extra calendar fields that used to be returned by Temporal.Calendar.prototype.fields() is now static; so no need to have the complicated PrepareTemporalFields operation that returns a null- prototype object with own data properties that correspond to arbitrary user fields. Dates in calendar space can be represented by a Calendar Fields Record with known fields. - Much of the special-casing to avoid user calls that was added in #2519 and similar PRs is now unobservable and is removed. Closes: #2836 Closes: #2853 Closes: #2854
This is a very large change, as it not only removes Temporal.Calendar and Temporal.TimeZone, but also tries to eliminate any extra complexity due to no longer having to deal with user code calls for calendar and time zone calculations. Some of the things that are removed or simplified include: - No more Calendar Method Records and Time Zone Method Records - In many places, no need to pass around the user's original options bag - In many places, no need to pass around the user's original PlainDate or Instant; use epoch nanoseconds, ISO Date Records, and ISO Date-Time Records instead - No more copying the own properties of options bags - Most of the calendar and time zone operations are now infallible - The set of extra calendar fields that used to be returned by Temporal.Calendar.prototype.fields() is now static; so no need to have the complicated PrepareTemporalFields operation that returns a null- prototype object with own data properties that correspond to arbitrary user fields. Dates in calendar space can be represented by a Calendar Fields Record with known fields. - Much of the special-casing to avoid user calls that was added in #2519 and similar PRs is now unobservable and is removed. Closes: #2836 Closes: #2853 Closes: #2854
This issue was split from #2826. This issue is solely focused on removing TimeZone. Please keep discussions on-topic.
Conclusion in the champions meeting of 2024-04-18. We've been asked to reduce the size and complexity of the proposal. The callable hooks in the time zone and calendar protocols are the part that implementations have been most uncomfortable with. They also seem to be where we get the biggest reduction in complexity for the least loss of use cases. The TimeZone and Calendar classes themselves make less sense to keep if the protocols are gone. So our conclusion is to remove them. This issue is focused on time zones only. A separate issue discusses calendars.
Motivations for removing custom time zones
TimeZone.from()
to "register" a custom ID. That ability was removed when the proposal went to stage 3 because the committee will not agree to global state.Temporal.TimeZone
object is heavily reduced. It could be removed and replaced with as little as one new method on the ZonedDateTime type.Use cases that would be deferred to a later proposal, and their replacements in the meantime
Work around incomplete/outdated support in TZDB
For example:
Replacement: Previously, you could implement a custom calendar or time zone by creating an object that implemented the protocol, and monkeypatching or wrapping some of Temporal so that it would deserialize dates with your custom calendar/time zone's ID into a Temporal object with the correct protocol object. You would now have to monkeypatch or wrap more of Temporal.
Converting directly between Instant and PlainDateTime
Replacement: Go through ZonedDateTime, instead of through TimeZone. e.g.
Determine if two time zone IDs are aliases
Replacement: Use ZonedDateTime.p.equals() with the same instant. (This is more inconvenient, but it's a pretty uncommon operation. If this really needs to be more ergonomic, a dedicated static method can be added in a follow up.)
Look up previous/next UTC offset transition in a time zone
Replacement: We'll add 1-2 methods to ZonedDateTime that replace the two methods on TimeZone.
Custom disambiguation behaviour
A niche use case is implementing PlainDateTime-to-Instant conversions with disambiguation behaviours other than the built-in
earlier
,later
,compatible
modes. By request, we have a cookbook recipe for this.Replacement: You can still do it with two conversions, for example:
Scope of issue
timeZone
property of object returned by ZonedDateTime's getISOFields() methods can only be a stringZonedDateTime.p.getTimeZoneTransition('next' | 'previous')
(or a pair of methods instead)The text was updated successfully, but these errors were encountered: