kotlinx-datetime
kotlinx-datetime copied to clipboard
WIP: Added ZonedDateTime
Initial sketch of
ZonedDateTime: common base classRegionDateTime: works for past and future dates and mimics how humans see datesOffsetDateTime: how many official specifications represent past/present dates
This is still missing a RegionTimeZone to represent time zones based on a region id instead of just an offset. Not implemented yet:
- parsing
- serialization
- support for adding/subtracting durations
- calculating the difference between two ZonedDateTimes
Also see discussion in #163
Feedback welcome.
- As defined,
ZonedDateTimeis just a collection of functions that are very easy to implement and doesn't offer much over just storingLocalDateTimeandTimeZoneseparately. If something is this easy to implement and doesn't meaningfully interact with the other entities in the library, there's little point in adding it to the base library. - It's unclear how
OffsetDateTimeandRegionDateTimecould be useful. When is it important to know what exactly does theZonedDateTimestore? If you need it for checking whether the time zone is fixed-offset, why not check the time zones themselves? OffsetDateTimeis probably not the best name for this, as it stores aFixedOffsetTimeZoneand not an offset.- As you yourself note,
instantis ill-defined, though for more problematic reasons:LocalDateTimetoTimeZoneconversion is ambiguous, whichZonedDateTimehides.
- As defined,
ZonedDateTimeis just a collection of functions that are very easy to implement and doesn't offer much over just storingLocalDateTimeandTimeZoneseparately. If something is this easy to implement and doesn't meaningfully interact with the other entities in the library, there's little point in adding it to the base library.
- We can serialize/deserialize, format/parse, sort and compare dates very easily. It's impossible or too difficult and error prone if we store those separately.
- This is a draft/WIP and I wanted to add support for adding/subtracting durations and other operations which map to how humans think about dates.
* It's unclear how `OffsetDateTime` and `RegionDateTime` could be useful. When is it important to know what exactly does the `ZonedDateTime` store? If you need it for checking whether the time zone is fixed-offset, why not check the time zones themselves?
When you want to use static types to enforce minimum requirements. We might want to ensure we store non-ambiguous RegionDateTime in the backend or maybe some OpenAPI endpoint only supports OffsetDateTime. Enforcing this with static types prevents mistakes and non-trivial bugs.
* `OffsetDateTime` is probably not the best name for this, as it stores a `FixedOffsetTimeZone` and not an offset.
That's just the name other APIs (e.g. java.time) use, but we can rename it to FixedOffsetDateTime. Though, IMHO OffsetTimeZone would've been a nicer name without the Fixed prefix and it's pretty clear that the offset is fixed.
* As you yourself note, `instant` is ill-defined, though for more problematic reasons: `LocalDateTime` to `TimeZone` conversion is ambiguous, which `ZonedDateTime` hides.
- It's not ambiguous with
OffsetDateTime. It's also not ambiguous withRegionDateTimewhen adding the optional offset (see the TODO) like java.time and the new JavaScript Temporal API do. Also it would be the correct building block for a calendar app where you often have to do date arithmetic (for repeating events). - It's the way humans think about time (and how a calendar app would work). So even if it's ambiguous, the ambiguity is just an edge case which can be resolved with RegionDateTime. In general it works well enough for humans. Also, this functionality is important and complex enough that we need an API for it.
- It's also not ambiguous with
RegionDateTimewhen adding the optional offset
In which case it would just be a OffsetDateTime right? And all the calendar usage traits would be gone.
- It's also not ambiguous with
RegionDateTimewhen adding the optional offsetIn which case it would just be a OffsetDateTime right? And all the calendar usage traits would be gone.
No, the UTC offset is used for disambiguation. The region is still needed. We need to handle these cases:
- A country decides to get rid of DST or introduce DST or change the DST offset (most of Europe is planning the first one, so your calendar entries better don’t break).
- A country moves its whole time zone offset.
- You want to refer to a moment within a winter<->summer time change.
For calendar applications the region would always take precedence and the offset would be used to disambiguate only. Example: Your wedding event in Italy in 2024 at 14:00 must keep its local time at 14:00 even if Europe gets rid of DST handling in the meantime. So, the offset must be ignored unless there's an ambiguity and even then it should only used to handle DST offsets and never be applied literally.
See also how others are doing it:
- https://tc39.es/proposal-temporal/docs/ambiguity.html#ambiguity-due-to-dst-or-other-time-zone-offset-changes
- https://docs.oracle.com/javase/8/docs/api/java/time/ZonedDateTime.html
The only open question is whether we should support a DST flag in addition to UTC based offsets. If a country moves its time zone offset and this overlaps with a DST switch then a UTC offset alone can't correctly disambiguate the hour during a DST change. Only a DST flag could handle that edge case. Maybe that's too much of an edge case though and it may not even be clear what the user's original intent was.
In that case I'd stick to the TC39 proposal, that looks quite good (there's also usually with at lot of peoples checking it).
I port some JVM-related code and this exact class is needed. Hope that it gets merged...
@kkocel most probably the Instant arithmetic, which already exists, will suit you: https://github.com/Kotlin/kotlinx-datetime#instant-arithmetic
@dkhalanskyjb actually I need to have a class that can be deserialized from the java.time.ZonedDateTime that comes from JVM backend