Will ZonedDateTime use the same winter time zone when daylight saving time is summer?

ZonedDateTime zdt = ZonedDateTime.of(2015, 10, 18, 0, 30, 0, 0, ZoneId.of("America/Sao_Paulo")); System.out.println(zdt); // 2015-10-18T01:30-02:00[America/Sao_Paulo] 

You can see that the hour is 1 , when we set the hour to 0 , and the time zone is UTC-02:00 , while the time zone should be UTC-03:00 .

But here is another example:

 ZonedDateTime zdt = ZonedDateTime.of(2015, 10, 18, 0, 30, 0, 0, ZoneId.of("America/Los_Angeles")); System.out.println(zdt); //2015-10-18T00:30-07:00[America/Los_Angeles] 

You can see that the time range of daylight saving time is UTC-07:00 , and the hour is 0 as we set.

Why are they different?

+5
source share
2 answers

As explained in @Misha's answer , this is due to daylight saving rules.

In Sao Paulo, the DST starts at midnight 2015-10-18: the clock moves forward 1 hour, so it “skips” from 23:59:59 to 01:00:00 . There is a space between 00:00:00 and 00:59:59 , so the time 00:30 adjusted accordingly.

You can check if the date and time for the time zone ZoneRules using the ZoneRules and ZoneOffsetTransition :

 ZoneId sp = ZoneId.of("America/Sao_Paulo"); ZoneRules rules = sp.getRules(); // check if 2015-10-18 00:30 is valid for this timezone LocalDateTime dt = LocalDateTime.of(2015, 10, 18, 0, 30); List<ZoneOffset> validOffsets = rules.getValidOffsets(dt); System.out.println(validOffsets.size()); // size is zero, no valid offsets at 00:30 

The getValidOffsets method returns all valid offsets for the specified date / time. If the list is empty, it means that the date / time does not exist in this time zone (usually due to the DST, the clock moves forward).

When the date / time exists in the time zone, the offset is returned:

 ZoneId la = ZoneId.of("America/Los_Angeles"); rules = la.getRules(); validOffsets = rules.getValidOffsets(dt); System.out.println(validOffsets.size()); // 1 - date/time valid for this timezone System.out.println(validOffsets.get(0)); // -07:00 

In Los_Angeles time zone, 1 valid offset is returned: -07:00 .

PS: Offset changes usually occur due to DST, but this is not always the case. DST and biases are determined by governments and laws, and they can change at any time. Thus, a gap in the allowable bias can also mean that such a change has occurred (some politician decided to change the standard bias of the country, so the gap may not necessarily be related to the DST).

You can also check when the change occurs, and what the offset is before and after it:

 ZoneId sp = ZoneId.of("America/Sao_Paulo"); ZoneRules rules = sp.getRules(); // get the previous transition (the last one that occurred before 2015-10-18 00:30 in Sao_Paulo timezone ZoneOffsetTransition t = rules.previousTransition(dt.atZone(sp).toInstant()); System.out.println(t); 

Output:

Transition [Gap on 2015-10-18T00: 00-03: 00 to -02: 00]

This means that the interval (the clock moves forward) is 2015-10-18T00:00 , and the offset will change from -03:00 to -02:00 (so that the clock moves 1 hour ahead).

You can also get all this information separately:

 System.out.println(t.getDateTimeBefore() + " -> " + t.getDateTimeAfter()); System.out.println(t.getOffsetBefore() + " -> " + t.getOffsetAfter()); 

Output:

2015-10-18T00: 00 → 2015-10-18T01: 00
-03: 00 → -02: 00

This shows that at 00:00 clock moves directly to 01:00 (therefore, 00:30 cannot exist). The second line is the offset before and after the change.


If you check the transitions in the Los_Angeles time zone, you will see that its DST starts and ends on different dates:

 ZoneId la = ZoneId.of("America/Los_Angeles"); rules = la.getRules(); // 2015-10-18 00:30 in Los Angeles Instant instant = dt.atZone(la).toInstant(); System.out.println(rules.previousTransition(instant)); System.out.println(rules.nextTransition(instant)); 

Output:

Transition [gap in 2015-03-08T02: 00-08: 00 to -07: 00]
Transition [Overlap on 2015-11-01T02: 00-07: 00 to -08: 00]

So, in the Los_Angeles time zone, DST starts on 2015-03-08 and ends on 2015-11-01 . Therefore, at 2015-10-18 all hours are valid (there is no adjustment, as happens in the Sao_Paulo time zone).


Some time zones have transition rules (for example, "DST starts on the third Sunday of October") instead of transitions (for example, "DST starts with this specific date and time"), and you can also use them if available:

 ZoneId sp = ZoneId.of("America/Sao_Paulo"); ZoneRules rules = sp.getRules(); // hardcoded: Sao_Paulo timezone has 2 transition rules, the second one is relative to October // but you should always check if the list is not empty ZoneOffsetTransitionRule tr = rules.getTransitionRules().get(1); // get the transition for year 2015 ZoneOffsetTransition t = tr.createTransition(2015); // use t the same way as above (the output will be the same) 

Another way to check if the date and time is valid for some time zone is to use the ZonedDateTime.ofStrict method, which throws an exception if the date and time is not valid for the time zone:

 ZoneId sp = ZoneId.of("America/Sao_Paulo"); ZoneId la = ZoneId.of("America/Los_Angeles"); LocalDateTime dt = LocalDateTime.of(2015, 10, 18, 0, 30); System.out.println(ZonedDateTime.ofStrict(dt, ZoneOffset.ofHours(-7), la)); // OK System.out.println(ZonedDateTime.ofStrict(dt, ZoneOffset.ofHours(-3), sp)); // throws java.time.DateTimeException 

The first case is normal, because the offset of -7 is valid for Los Angeles on a given date / time. The second case throws an exception because the offset -3 not valid for São Paulo at a given date / time.

+3
source

This is because the time you have chosen falls between midnight and 01:00 on the night when Brazil switches to daylight saving time. This time is actually impossible, and you will get the behavior described in the documentation :

In the case of a gap when the clock moves forward, there is no actual bias. Instead, the local date-time is set to a later space length. For a typical change in the daily transition by 1 hour, local time-time will be moved one hour later to the offset, usually corresponding to the "summer" time.

You can observe the same behavior in the Los_Angeles zone by selecting a time between 02:00 and 03:00 on the corresponding night in March:

 zdt = ZonedDateTime.of(2015, 3, 8, 2, 30, 0, 0, ZoneId.of("America/Los_Angeles")); System.out.println(zdt); 
+7
source

Source: https://habr.com/ru/post/1269216/


All Articles