tc39 / proposal-temporal

Provides standard objects and functions for working with dates and times.
https://tc39.es/proposal-temporal/docs/
Other
3.35k stars 153 forks source link

Why did you drop ZonedDateTime ? #84

Closed pithu closed 5 years ago

pithu commented 6 years ago

In the commit that removed ZonedDateTime from the README.md there is no comment about it and i couldn't find any discussions about that topic. Should ZonedInstant be a replacement ?

A date/ time API should define a consistent language for domains, that makes time and date values easy to manage, manipulate, and understand. ZonedDateTime, as defined in the JSR-310 API, comply quite well with such requirements. It contains the local time, a timezone and an offset. Together with the methods withZoneSameInstant, withZoneSameLocal, withEarlierOffsetAtOverlap and withLaterOffsetAtOverlap it is quite easy to untangle even complicated use case, e.q.:

// JSR-310 API

// Alert at 2018-08-14 14:30 Berlin local time 
const zonedDateTime = 
    LocalDateTime.parse('2018-08-14T14:30').atZone(ZoneId.of('Europe/Berlin'))

// A live talk starts in Berlin 2018-08-14 at 15 o'clock local time.
// What local time in New York i have to attend ?
const localTimeInNewYorkWhenTalkStarts = 
    LocalDateTime
        .parse('2018-08-14T14:30')
        .atZone(ZoneId.of('Europe/Berlin'))

        // convert ZonedDateTime to different time zone, 
        // but keep point in the timeline
        .withZoneSameInstant(ZoneId.of('America/New_York'))

        // convert to local time
        .toLocalDateTime()
// "2018-08-14T08:30"

An Instant is a point in the timeline with the UTC timezone. Isn't a Instant more a technical thing, for technical use cases, like for comparing timestamps from different sources at server side. How can i define 'human readable' use cases with it ?

And isn't a ZonedInstant the same as an Instant, both define a point in the timeline at a certain timezone ?

pipobscure commented 6 years ago

Instant is a moment in time without any notion of timezones. ZonedInstant is an Instant with a timezone.

From a ZonedInstant you can then get a GregorianDateTime, GregorianDate or GregorianTime. Or in future a HebrewDateTime or an EthiopianTime or a CopticTime or a JulianDate or ...


Just as a thought, ZonedDateTime in JSR-310 entirely ignores different calendars. So it's actually not a good solution. I think our current split is much better than JSR-310.

pithu commented 6 years ago

An Instant is a point in the timeline at UTC, so a ZonedInstant at UTC is the equal to an Instant, therefore having an extra domain Instant together with a ZonedInstant is somehow redundant or superfluous.

I don't see your point that is better suited to define different calendar systems. A ZonedInstant and a ZonedDateTime both express a point in the timeline and you can convert on into the other.

But the main difference is that ZonedDateTime is much better suited to give, me as a developer a domain language to describe my real world, day to day issue. Its start from a Local/ Civil/ Simple/ however DateTime and adds whats missing there, the timezone and the offset to UTC.

pipobscure commented 6 years ago

Instant is defined as the number of periods of radiation of the cesium133 atom since a specific point in time measured in units of “9,192,631,770 periods of radiation” or si-fractions thereof.

There is no timezone involved.

ZonedInstant takes such an Instant and places it within a timezone.

The ISO/Gregorian object allow that instant to be represented in accordance with a specific calendar/time representation.

In other words none of them are superfluous; They each have distinct meaning and use.

The reason I like ISO as a prefix, is because the calendar/time representation used is that of the ISO-8601 standard (i.e. proleptic Gregorian calendar i. combination with 24hr midnight based days).

Other calendar systems are:

Ethiopian: proleptic Gregorian calendar with 12h 6am-6pm-6am days

Hebrew, Coptic, Chinese, ...

Which will be represented in distinct objects that work in cooperation with ZonedInstant.

These calendar/time systems have no notion of timezones in themselves. They are always localtime. So they need to work with a ZonedInstant.

I hope that clears up the distictions.

On 23 Sep 2018, at 11:15, Philipp Thuerwaechter notifications@github.com wrote:

An Instant is a point in the timeline at UTC, so a ZonedInstant at UTC is the equal to an Instant, therefore having an extra domain Instant together with a ZonedInstant is somehow redundant or superfluous.

I don't see your point that is better suited to define different calendar systems. A ZonedInstant and a ZonedDateTime both express a point in the timeline and you can convert on into the other.

But the main difference is that ZonedDateTime is much better suited to give, me as a developer a domain language to describe my real world, day to day issue. Its start from a Local/ Civil/ Simple/ however DateTime and adds whats missing there, the timezone and the offset to UTC.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub, or mute the thread.

pithu commented 6 years ago

What you saying about Instant confuse me, i have no idea what you talking about and its not fitting to the docu here.

pipobscure commented 6 years ago

@pithu sorry for having been unclear. I was trying to explain the conceptual distinctions.

“9,192,631,770 periods of radiation” is the official definition of a second. The reason I chose that for of expression was to make it distinct. Obviously I failed in clarifying the distinctness of the concepts.

I wanted to clear up that Instant is meant to be a simple measurement type. One from which no direct corollary to a specific Date/Time is to be drawn. Once one realises that it's just seconds since a specific point in time, I thought it become clearer that an Instant is not really meant as a point in the UTC-timeline, but rather an abstrct way to determine a specific point in time independent of timezone.

Only once you add a timezone and make it a ZonedInstant, do date-calculations become a thing.

I hope that's a bit clearer. If not please do nag, and I'll ty again.

rxaviers commented 6 years ago

@pipobscure I am also confused about Instant definition...

Instant is defined as the number of periods of radiation of the cesium133 atom since a specific point in time measured in units of “9,192,631,770 periods of radiation” or si-fractions thereof.

There is no timezone involved.

If there's no timezone involved, what's the starting point ("since a specific point in time")? It seems to me there's a reference time and it's based on a timezone, isn't it?

gibson042 commented 6 years ago

An instant is a point in time independent of location. The POSIX epoch is 1970-01-01T00:00Z, which is exactly the same as e g. 1969-12-31T19:00-05:00, and other instants are defined in relation to it. Or put another way, the addition of location data doesn't change the value of an instant, it just changes the preferred representation.

jamiewinder commented 6 years ago

Since defining an instant clearly involves stressing the zoneless nature of it, isn't ZonedInstant a bit of a weird term to comprehend? (i.e. "A zoneless point in time, with a zone").

rxaviers commented 6 years ago

@gibson042 it's independent of location, but NOT of timezone, hence Z (which means Zulu, i.e., UTC) in 1970-01-01T00:00Z. What I am insisting here is that I also agree there's a confusion differentiating Instant from ZonedInstant, because it seems like Instant is just a ZonedInstant in UTC. There's no such zoneless point in time if you think about it.

ljharb commented 6 years ago

Having a separate type for Instant is critical for conveying the semantic that the time zone doesnt matter. A zoned instant in UTC does not convey that.

gibson042 commented 6 years ago

I dispute that a separate type is critical for conveying that semantic (as opposed to e.g. nullable time zone data on a single Instant type), but the semantic itself does seem to matter and is not captured by setting time zone to UTC.

pipobscure commented 6 years ago

@rxaviers Z does not mean Zulu! Zulu is simply the NATO alphabet way of saying Z. It means Zero Hours and denotes the time-offset from prime meridian.

As such it's not a time-zone. It's actually a Zero-Time-Zone of sorts.

pipobscure commented 6 years ago

Which incidentally is also the reason why:

const instant = new Instant(0n);
instant.toString(); // 1970-01-01T00:00:00.000000000Z
instant.withZone('UTC').toString(); // 1970-01-01T00:00:00.000000000+00:00
rxaviers commented 6 years ago

Thanks for the clarification. Now, I understand the theoretical difference between Z (meaning Zero Hours, no time zone) and UTC (meaning +00:00).

rxaviers commented 6 years ago

@gibson042, I'm taking the liberty to "move" your comment https://github.com/tc39/proposal-temporal/issues/84#issuecomment-423997000 above here: https://github.com/tc39/proposal-temporal/issues/42#issuecomment-424042545

gibson042 commented 6 years ago

Which incidentally is also the reason why:

const instant = new Instant(0n);
instant.toString(); // 1970-01-01T00:00:00.000000000Z
instant.withZone('UTC').toString(); // 1970-01-01T00:00:00.000000000+00:00

This is an extremely subtle distinction that therefore needs to be a prominent aspect of documentation and discussions around the proposal.

Z and +00:00 mean precisely the same thing in RFC 3339, and if anything ISO 8601-1 prefers the former for UTC ("The zone designator is empty if use is made of local time in accordance with 4.2.2.2 through 4.2.2.4, it is the UTC designator [Z] if use is made of UTC of day in accordance with 4.2.4 and it is the difference-component if use is made of local time and the difference from UTC in accordance with 4.2.5.2").

mattjohnsonpint commented 6 years ago

Instant is defined as the number of periods of radiation of the cesium133 atom since a specific point in time measured in units of “9,192,631,770 periods of radiation” or si-fractions thereof.

I disagree. Since we are not supporting leap seconds in this API, Instant is not a pure measure of SI seconds. It is more akin to Unix Time, in that leap seconds are treated as if they did not happen.

... an Instant is not really meant as a point in the UTC-timeline, but rather an abstrct way to determine a specific point in time independent of timezone.

Actually, it is a point on the UTC timeline. It's just that the UTC timeline also includes :60Z values for leap seconds, and those are not represented here. Just because :60Z second values are not represented, does not negate that other second values :00Z through :059Z are valid and map to their exact positions on the UTC timeline.

Z does not mean Zulu! Zulu is simply the NATO alphabet way of saying Z. It means Zero Hours and denotes the time-offset from prime meridian.

As such it's not a time-zone. It's actually a Zero-Time-Zone of sorts.

Thus, IMHO "Zulu" is not incorrect but we should not use it normatively. I prefer we use the term "UTC Designator" as per ISO 8601.

mattjohnsonpint commented 6 years ago

As to Instant vs ZonedInstant, indeed one could get similar results with ZonedInstant and UTC or +00:00 as the time zone. However, there are two key differences:

As to why ZonedInstant rather than ZonedDateTime, this is more subtle, but my main reasoning is that there is always an unambiguous point in time behind a ZoneDateTime, thus it is not like the Civil types.

This is rather confusing with ZonedDateTime in other implementations. For example, Java's says:

In terms of design, this class should be viewed primarily as the combination of a LocalDateTime and a ZoneId. The ZoneOffset is a vital, but secondary, piece of information, used to ensure that the class represents an instant, especially during a daylight savings overlap.

If it's vital, why is it secondary? If it is to "ensure that the class represents an instant", then why is it not internally using an Instant and ZoneId? If there's some critical advantage of using a LocalDateTime + ZoneOffset internally, I don't see it.

gibson042 commented 6 years ago

Actually, it is a point on the UTC timeline. It's just that the UTC timeline also includes :60Z values for leap seconds, and those are not represented here.

That means instants are on have a fixed offset from the TAI timeline, not UTC. And the consequences are observable—e.g., 2016-12-31T23:59:59Z precedes 2017-01-01T00:00:00Z by one second in TAI but two seconds in UTC.

mattjohnsonpint commented 6 years ago

Except that TAI is 37 seconds ahead of UTC, and thus 2017-01-01T00:00:00Z on the UTC timeline maps to 2017-01-01T00:00:37Z on the TAI timeline. We are following the UTC timeline, despite the discontinuities created by leap seconds.

I'll point out that just about every major date/time API from any implementation in any language behaves this way, including ECMAScript's current Date API. Very few follow TAI or track leap seconds. We are not looking to do anything different here.

rxaviers commented 6 years ago

Instant values are all normalized to the same time zone, thus their values are inherently sortable, comparable, and equatable (through whatever API) without any ambiguity or further normalization.

@mj1856 please can you explain this further? It seems like the approach to compare them (Instant and ZonedInstant) is still undecided. In case they are compared by their instants, this statement is irrelevant, right?

gibson042 commented 6 years ago

@mj1856 updated for clarity. My point is that the proposal actually does not use the UTC timeline at all, but rather operates on a timeline with a constant offset from TAI (similar to GPS time and POSIX time) was wrong because I conflated the second counting of TAI with the day counting of POSIX time. But in either case, it's fine and actually important that everything works without a built-in awareness of the specific discontinuities introduced into UTC by leap seconds.

pipobscure commented 6 years ago

Thanks everybody. Learining a lot here. My intent was only to establish a mental model of how to think about these objects.

Let me know what the thoughts are on the following statements:


Instant represents a specific point in time while ignoring leap-seconds. This is akin to POSIX time (which uses the same number for the second-60 as for second-59 if inserting a leap-second). This is only roughly aligned to UTC due to the earth being fairly wobly and UTC-having leap-seconds due to it using SI seconds. POSIX uses 1/86400 days as seconds instead so that leap-seconds don't occurr because seconds themselves are of indeterminate length due to the earth wobbling a bit.

The most distinguishing feature of Instant is that like POSIX time is simply a numeric counter that counts forward at the rate of 86400 units per day (though this is done at a higher precision using metric sub-units). As such it has no inherent concept of "days", "months", "hours", etc... It is only for serialisation/deserialisation purposes that these concepts arise and only by translating POSIX time to UTC and serializing as ISO-8601 strings and deserializing the same route back.


ZonedInstant is our bastard child that we created because we needed an intermediary between Instant and possible date/time representations. No-one really loves it, no-one really wants it, but where else do we put the timezone?

So we had to stuff the timezone somewhere without polluting either Instant nor the XXXDateTime classes so someone came up with just creating another box. I imagine the conversation like:

P1: Let's just create a separate class/box to combine an instant and a timezone then P2: Sort of like an Instant that has been owned ... P1: ... or zoned more like. P2: Eureka! we'll call it ZonedInstant P1: Why not ZonedDateTime? P2: Because it doesn't have a "Date" or a "Time". Just an Instant and a Zone.

Well that's what I'd like to imagine at least. 😄


XXXDate, XXXTime, XXXDateTime are the representations of the concept of calendars and clocks (dates & times). For starters we'll only concern ourselves with what we for now call CivilDate, CivilTime, CivilDateTime which employs the proleptic Gregorian calendar with 24h midnight days. In future we can create additional objects to implement other systems.

This is the first time that the concepts of days, months, years, hours, etc actually enter the conversation.



If someone could correct the likely errors in this mental model, I'd appreciate it.

gibson042 commented 6 years ago

The most distinguishing feature of Instant is that like POSIX time is simply a numeric counter that counts forward at the rate of 86400 units per day (though this is done at a higher precision using metric sub-units).

Yes, and thank you for pointing that out because I was forgetting it.

We don't want [time zone] in Instant since that would change the fundamental character of Instant.

I disagree that the fundamental character would change, and am currently in favor of allowing Instant to carry time zone information.

We don't want it int the actual Date/Time/DateTime classes, since these are independant of timezone

Right, adding time zone to the other classes would change their fundamental character.

pipobscure commented 6 years ago

@gibson042 how would adding a timezone not change the fundamental identity of Instant as a monotonically increasing count of "seconds" since the POSIX-Epoch?

What I'm thinking of is more is that we may want to eliminate ZonedInstant entirely and instead:

let xmpl = new CivilDateTime(2018, 9, 26, 13, 8);
let inst = xmpl.toInstant('America/New_York'); // 1537981740000

inst.toString(); // 2018-09-26T17:09:00.000Z
inst.toString('America/New_York'); // 2018-09-26T13:08:00.000-04:00[America/New_York]
inst.toString('UTC'); // 2018-09-26T17:09:00.000+00:00[UTC]

xmpl = CivilDateTime.fromInstant(inst, 'UTC');
xmpl.hour // 17
xmpl.minute // 8

xmpl = CivilDateTime.fromInstant(inst, 'America/New_York');
xmpl.hour // 13
xmpl.minute // 8

Is there any sincere benefit of keeping the timezone around permanently?

ljharb commented 6 years ago

Just like it’s important to have the calendar be an identity you can pass around with it’s associated object, it’s important to have the time zone be preserved in the same way. Forcing it to be an independent string that i have to pass around separately doesn’t seem like a win.

pipobscure commented 6 years ago

@ljharb does that mean that my jovial characterisation of ZonedInstant in my previous post is actually accurate? Yikes!!!

ljharb commented 6 years ago

I wasn’t part of those deliberations, but there’s very much a use case of “i need an instant, with a zone” that necessitates it being its own object, regardless of naming.

rxaviers commented 6 years ago

@pipobscure,

The most distinguishing feature of Instant is that like POSIX time is simply a numeric counter that counts forward at the rate of 86400 units per day

Would that change for any given timezone?

pipobscure commented 6 years ago

No, timezone would not change the meaning at all. By that I mean that:

Then number of seconds is the same for these:

2018-09-26T13:08:00.000-04:00[America/New_York] from 1969-12-31T20:00:00.000-04:00[America/New_York]

2018-09-26T18:08:00.000+01:00[Europe/Berlin] from 1970-01-01T01:00:00.000+01:00[Europe/Berlin]

2018-09-26T17:08:00.000Z from 1970-01-01T00:00:00.000Z

So the timezone is entirely immaterial. It's just entirely irrelevant.

In my opinion it detracts the purity of Instant a bit. It also removes the simply from that statement.

pipobscure commented 6 years ago

Which incidentally reminds me of a question:

What should the milliseconds value of a ZonedInstant be? Is it identical to that of its Instant or is it the milliseconds since the 1st of January 1970 at 00:00:00.000 LocalTime?

rxaviers commented 6 years ago

Thanks...

What should the milliseconds value of a ZonedInstant be? Is it identical to that of its Instant or is it the milliseconds since the 1st of January 1970 at 00:00:00.000 LocalTime?

What would be the value of this transformation?

ljharb commented 6 years ago

The meaning it adds is “where is this instant” - it adds locality.

Being on a separate object means that nothing detracts from Instant.

pipobscure commented 6 years ago

@rxaviers the value of that transformation would be nothing.

I am asking the question in an attempt to understand why there is this claim in some of the issues that Instant is intrinsically sortable while ZonedInstant is not; whether two ZonedInstants with the same Instant but differing time-zones are equal;

To my simple understanding two ZonedInstants with the same Instant are loose-equal, with an identical time-zone they'd be strict-equal, and sorting should sort by Instant first offset only as a secondary characteristic.

rxaviers commented 6 years ago

Thanks. Yeap, we need to defined how Instant and ZonedInstant comparison works (cross link https://github.com/tc39/proposal-temporal/issues/42#issuecomment-424486284)

gibson042 commented 6 years ago

how would adding a timezone not change the fundamental identity of Instant as a monotonically increasing count of "seconds" since the POSIX-Epoch?

@pipobscure Because the internal time value of an Instant is preserved with or without adding a time zone annotation.

there’s very much a use case of “i need an instant, with a zone” that necessitates it being its own object, regardless of naming.

@ljharb Its own object, yes. But are you saying that the use case of “i need an instant, with a zone” would not be fulfilled by a single Instant class whose instances supported optional time zone data?

gibson042 commented 6 years ago

To my simple understanding two ZonedInstants with the same Instant are loose-equal, with an identical time-zone they'd be strict-equal, and sorting should sort by Instant first offset only as a secondary characteristic.

@pipobscure we can't achieve even Instant.fromString("1970-01-01T00:00Z") == Instant.fromString("1970-01-01T00:00Z") with the current Abstract Equality Comparison algorithm because object-to-object comparisons end up in SameValueNonNumber, but we can achieve instant1 >= instant2 && instant1 <= instant2.

pipobscure commented 6 years ago

I just argued in #68 that we definitely need something like ZonedCivilDateTime which may eliminate the need for ZonedInstant, having come to the conclusion (temporary though it may be) that ZonedInstant is not the right approach. However rather than having ZonedDateTime I'd suggest ZonedCivilDateTime making it part of the Civil family of objects rather than align it with Instant.

Thoughts welcome!!!!

mattjohnsonpint commented 6 years ago

Added thoughts there. Thanks.

pithu commented 6 years ago

Hi @mj1856, thanks for coming back to my actual question in your comment above.

I absolutely agree that Instant values are normalized, comparable points in the timeline and therefore the domain is a must. Introducing a ZonedInstant has a code smell of redundancy but that is not my point.

IMO ZonedDateTime is much better suited then ZonedInstant to describe my day to day issues for several reasons:

jodastephen commented 6 years ago

I first commented on the set of value types a long time ago. Since then there seems to be general agreement that this API can cope with about 4 main types at present. From my experience, it is pretty clear that those 4 types should be:

Together these provide the minimal set of types necessary to do useful date-time math/work. (Any fewer, and the API would fail to meet basic needs in my view)

Instant is most useful for historic events - a timestamp recording exactly when something occurred. For example, a time-zone can be used when the event is viewed in a GUI (and different users might view the event as having happened at a different local time, even though it was the same instant). By minimising what you can do with it (no addition of months/years) it gains clarity and strength as a concept.

LocalDate is most useful for business logic, particularly where legal contracts are involved. In many cases, a contract will run from a certain date to another date. For example, a financial trade or insurance.

LocalTime is also useful for business logic, covering the time aspect of contracts. For example, "your car insurance is valid until midday on the date of expiry".

ZonedDateTime is the essential part for all the nasty hairy DST time-zone math. Its exists to allow a period of years/months/days to be added while taking into account the time-zone. It also allows questions like if I take off at 09:00 on Monday and the flight takes 10 hours what local time will it be when I land in Rio? Or am I currently in a DST overlap where the same local time happens twice? The methods withZoneSameInstant, withZoneSameLocal, withEarlierOffsetAtOverlap and withLaterOffsetAtOverlap are all key to tackling the really hard date-time math problems - sorry, but there are no shortcuts here.


In JSR-310, ZonedDateTime is built on LocalDate, LocalTime, an offset (+01:00) and a time-zone. So why not a ZonedInstant built on Instant and a time-zone?

Well as I indicate above, the reason for wanting the type in the first place is to do date-time math on it. ie. math on date and time. If you just want math on an instant then just use Instant. ie. the time-zone only has any relevance when considering the impact on date and time fields (particularly years/months). And by corollary, an Instant can't take into account DST effects (except by passing the zone in to each method call, which is just a horrible user experience).

Does this API have to use the same four fields internally as JSR-310? No. but I found that the most efficiently approach in JSR-310 given the primary use case of date-time math. Having to constantly convert from an Instant to date-time fields and back again to do the math would have been slow and unappealing. I suspect the same is true here, but it is much more important to focus on the API methods rather than the state the type contains.

And the name? Well since its raison d'etre is to manipulate date and time with zone effects, ZonedDateTime is about as good a name as you'll get.

gibson042 commented 6 years ago

I would like to see reasonable side-by-side comparisons of ZonedInstant vs. ZonedDateTime, including cases with DST effects because that's where the difference is likely to matter most.

pipobscure commented 6 years ago

After long discussion I think we have come to the conclusion reflected in #97 and the polyfill.

TL;DR

The object should be ZonedDateTime and follow the proleptic Gregorian calendar with a 24h midnight based day. It is the object that ties Instant objects to a specific calendar implementation. So you could see it as the glue that binds Instant to the Civil-family.

pipobscure commented 6 years ago

Can we close this?

pithu commented 5 years ago

It looks like you simply renamed ZonedInstant to ZonedDateTime, but did not change the specification.

You specified ZonedDateTime as 'A point on the universal timeline, with an associated time zone.' If you stick to that spec, please call it ZonedInstant! That name fits much better. And otherwise you would make the confusion complete for all developers that knows Java and Javascript. You would not only use different names for the same domains (because you use Civil instead of the Local Prefix) but also use the same name for different domains.

A ZonedDateTime as defined in JSR-310 is a local date-time with a time-zone and a zone offset used to handle ambiguous local date-times. That's something different. And as already stated above, in my opinion the ZonedDateTime domain is much more suitable to express real world developer problems.

jodastephen commented 5 years ago

I'll restate what I said earlier:

Does this API have to use the same four fields internally as JSR-310? No. but I found that the most efficient approach in JSR-310 given the primary use case of date-time math. Having to constantly convert from an Instant to date-time fields and back again to do the math would have been slow and unappealing. I suspect the same is true here, but it is much more important to focus on the API methods rather than the state the type contains.

ie. the state is less important than the API methods. (But I do think the class should be described in terms of date and time, not instant).

gibson042 commented 5 years ago

There are some important differences between Instant and ZonedDateTime, although not all of #120 has yet made it into the README and spec text.

How would you change that?

pithu commented 5 years ago

I would expect that the API allows me to construct a ZonedDateTime with a given local datetime and a timezone. eg. const zonedDateTime = someLocalDateTime.atZone(europeBerlin). Thats for me the natural way how to express a certain point in time. 'I am sitting at a certain location, looking at a calender and a clock at the wall'.

Therefore i would describe a ZonedDateTime as a local date time with a timezone and specify a strategy how to handle ambiguous local date-times, how to calculate an offset/ instant for the three cases: normal, gap and overlap during daylight saving transitions. Like for example in JSR-310 its specified that in an overlap situation the previous offset will be retained, if possible.

Adding the additional methods withEarlierOffsetAtOverlap() and withLaterOffsetAtOverlap() might be raryly used, but give me the control to pick the desired instant and helps a lot to understand how the API works.

And i would add the two methods .withZoneSameInstant(timeZone) and .withZoneSameLocal(timeZone). That allows to write up calculations in a very readable way.

gibson042 commented 5 years ago

I would expect that the API allows me to construct a ZonedDateTime with a given local datetime and a timezone. eg. const zonedDateTime = someLocalDateTime.atZone(europeBerlin). Thats for me the natural way how to express a certain point in time. 'I am sitting at a certain location, looking at a calender and a clock at the wall'.

That should be possible like const zonedDateTime = (new CivilDateTime(2019, 5, 30, 14, 45)).withZone("Europe/Berlin").

Therefore i would describe a ZonedDateTime as a local date time with a timezone and specify a strategy how to handle ambiguous local date-times, how to calculate an offset/ instant for the three cases: normal, gap and overlap during daylight saving transitions. Like for example in JSR-310 its specified that in an overlap situation the previous offset will be retained, if possible.

Right, just like we need disambiguation control for month/year arithmetic in plus, we also need it for offset transitions in both plus and withZone.

Adding the additional methods withEarlierOffsetAtOverlap() and withLaterOffsetAtOverlap() might be raryly used, but give me the control to pick the desired instant and helps a lot to understand how the API works.

I personally feel like those are better handled as available disambiguation values for the existing methods rather than as new methods.

And i would add the two methods .withZoneSameInstant(timeZone) and .withZoneSameLocal(timeZone). That allows to write up calculations in a very readable way.

I don't know if we'll go this far. Assuming you already have a {Offset,Zoned}DateTime dt, the former can be dt.instant.withZone(timeZone) and probably also dt.withZone(timeZone) (at least per current documentation in which instant data is preferred over civil), while the latter can be CivilDateTime.from(dt).withZone(timeZone).

tjcrowder commented 5 years ago

(Coming to this very late.) To be clear: The plan is to have ZonedDateTime, right? This issue is only still open because...there are API issues to resolve? It's just confusing (to me) to have an open issue called "Why did you drop ZonedDateTime?" when ZonedDateTime is prominently explained in the explainer, part of the current object models shown, etc. :-) TIA