I am currently looking at ZonedDateTime behaviour when the date is inside and outside British Summer Time.
The British Summer Time starts on 25th of March and it adds one hour (+1).
I have created few instances of ZonedDateTime (UTC and Europe/London) and next I have added to them 1 month so that they fall into ZonedDateTime.
// These dates will be outside British Summer Time
ZonedDateTime utcFirstMarch = ZonedDateTime.of(2018, 3, 1, 12, 0, 0, 0, ZoneId.of("UTC"));
ZonedDateTime londonFirstMarch = ZonedDateTime.of(2018, 3, 1, 12, 0, 0, 0, ZoneId.systemDefault());
// These dates will be inside British Summer Time
ZonedDateTime utcFirstMarchPlusMonth = ZonedDateTime.of(2018, 3, 1, 12, 0, 0, 0, ZoneId.of("UTC")).plusMonths(1);
ZonedDateTime londonFirstMarchPlusMonth = ZonedDateTime.of(2018, 3, 1, 12, 0, 0, 0, ZoneId.systemDefault()).plusMonths(1);
ZonedDateTime londonFirstMarchPlusMonthToUtc = ZonedDateTime.of(2018, 3, 1, 12, 0, 0, 0, ZoneId.systemDefault()).plusMonths(1).withZoneSameInstant(ZoneId.of("UTC"));
This is the result when I print these dates:
utcFirstMarch: 2018-03-01T12:00Z[UTC]
londonFirstMarch: 2018-03-01T12:00Z[Europe/London]
utcFirstMarchPlusMonth: 2018-04-01T12:00Z[UTC]
londonFirstMarchPlusMonth: 2018-04-01T12:00+01:00[Europe/London]
londonFirstMarchPlusMonthToUtc: 2018-04-01T11:00Z[UTC]
Finally I have printed out epoch seconds for each of the dates:
utcFirstMarch: 1519905600
londonFirstMarch: 1519905600
utcFirstMarchPlusMonth: 1522584000
londonFirstMarchPlusMonth: 1522580400
londonFirstMarchPlusMonthToUtc: 1522580400
I know that ZonedDateTime is immutable. This means that when I add one month I actually create a new instance with changed month. Could you please tell me whether my assumptions for the given observations are correct:
Adding one month will create a new instance of ZonedDateTime. The hour on the ZonedDateTime will always be the same. Doesn't matter if new date is in BST or not. (Look at LondonFirstMarch and LondonFirstMarchPlusMonth)
Because after adding 1 month londonFirstMarchPlusMonth falls into BST in order for it to still be 12:00 it has actually extract one hour. This means that the underlying epoch seconds will be different to utcFirstMarchPlusMonth.
Finally londonFirstMarchPlusMonthToUtc when we converted the zone to be UTC it showed that the actual hour is 11:00.
Edit:
Perhaps I was not clear enough - apologies. One month was arbitrary value so that when added to the first date produces second date falling under BST.
And as mentioned perhaps one month was not a good example as it means different things depending on which month we are in. The point for me was that the "month" will be composed of 24 hour units. (Exactly as Ole.v.v. said)
I think operating on UTC time and optionally converting it to Europe/London is the solution to "my questions"
Your assumptions are generally correct. A few comments.
For 1., ZonedDateTime
will try to keep the hour the same. Only if this is not possible, it will do something else. For example, one might expect the following to print a time 01:30:
System.out.println(ZonedDateTime
.of(2018, 2, 25, 1, 30, 0, 0, ZoneId.of("Europe/London"))
.plusMonths(1));
It prints
2018-03-25T02:30+01:00[Europe/London]
In the transition to summer time the time is moved forward from 1 to 2 AM, so there is no time of 1:30 that day. ZonedDateTime
does not produce a non-existing time, so it picks 02:30 instead in this case.
For 4., “exactly one month” is a little hard to define rigorously since a month may be 28, 29, 30 or 31 days. But if you want a multiple of 24 hours, using UTC will give you that.