-
Notifications
You must be signed in to change notification settings - Fork 169
Description
Conclusion in the champions meeting of 2024-04-18. We've been asked to reduce the surface area 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.
Motivations for removing
- Requiring observable calls in a particular sequence makes it difficult for implementations to optimize, unless they maintain separate code paths for built-in vs. user-supplied calendars/time zones.
- Large increase in complexity of proposal for relatively little gain.
- This functionality made more sense back when you could monkeypatch Calendar.from() and 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.
- Without a calendar protocol, there doesn’t seem to be much point in having a Temporal.Calendar object. All the functionality is still easily available through PlainDate methods and properties, (except for Calendar.p.fields() and Calendar.p.mergeFields() which are weird methods that only exist to make it possible to build custom calendars with extra fields.)
- Without a time zone protocol, the usefulness of a
Temporal.TimeZone
object is heavily reduced, although it doesn’t become completely redundant likeTemporal.Calendar
.
Use cases that disappear, and their replacements
Work around incomplete/outdated support in CLDR calendars and TZDB
For example:
- Adjustment days in Hijri calendars
- https://github.com/khawarizmus/hijri-week-calendar
- Make sure program runs against known version of time zone database regardless of whether environment is ahead or behind
Replacement: Previously, you could implement a custom calendar or time zone by creating an object that implemented the protocol, and monkeypatching 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 more of Temporal. As part of moving this issue forward, we'll create a proof of concept for doing this, to make sure that it remains possible.
Converting directly between Instant and PlainDateTime
Replacement: Go through ZonedDateTime, instead of through TimeZone. e.g.
// Before
timeZone.getPlainDateTimeFor(instant)
timeZone.getInstantFor(plainDateTime, { disambiguation })
// After
instant.toZonedDateTimeISO(timeZoneID).toPlainDateTime()
plainDateTime.toZonedDateTime(timeZoneID, { disambiguation }).toInstant()
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.)
// Before
Temporal.TimeZone.from('Asia/Kolkata').equals(Temporal.TimeZone.from('Asia/Calcutta'))
// After
zonedDateTime.withTimeZone('Asia/Kolkata').equals(zonedDateTime.withTimeZone('Asia/Calcutta'))
Look up previous/next UTC offset transition in a time zone
Replacement: We'll add two methods to ZonedDateTime that replace the two methods on TimeZone.
// Before
timeZone.getNextTransition(fromInstant)
timeZone.getPreviousTransition(fromInstant)
// After
const fromZonedDateTime = fromInstant.toZonedDateTimeISO(timeZoneID);
fromZonedDateTime.nextTransition()
fromZonedDateTime.previousTransition()
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:
// Before
arrayOfInstants = timeZone.getPossibleInstantsFor(plainDateTime)
// After
arrayOfInstants = [
plainDateTime.toZonedDateTime(timeZoneID, { disambiguation: 'earlier' }),
plainDateTime.toZonedDateTime(timeZoneID, { disambiguation: 'later' }),
]
Scope of issue
- Remove Temporal.Calendar
- Remove Temporal.TimeZone
- User-defined methods are not looked up nor called during calculations
- Calendar-taking APIs no longer accept objects, only string IDs, and ISO 8601 strings out of which a string ID is determined
- Time-zone-taking APIs no longer accept objects, only string IDs, and ISO 8601 strings out of which a string ID is determined
- [[Calendar]] internal slot of PlainDate, PlainDateTime, PlainYearMonth, PlainMonthDay, ZonedDateTime only stores string ID
- [[TimeZone]] internal slot of ZonedDateTime only stores string ID
- Remove getCalendar() methods from PlainDate, PlainDateTime, PlainYearMonth, PlainMonthDay, ZonedDateTime prototypes
- Remove ZonedDateTime.p.getTimeZone()
calendar
property of object returned by PlainDate, PlainDateTime, PlainYearMonth, PlainMonthDay, ZonedDateTime's getISOFields() methods can only be a stringtimeZone
property of object returned by ZonedDateTime.p.getISOFields() can only be a string- Add ZonedDateTime.p.nextTransition() and ZonedDateTime.p.previousTransition()
- Update TypeScript types to match the changes above.
- Create proof of concept for how you would polyfill a custom calendar or time zone going forward