javajava-timelocaldatetimejava.time.instant

Why is conversion from LocalDateTime to Instant not working?


Do you know why 4. and 6. prints have wrong hours in following code?

LocalDateTime ldtNow = LocalDateTime.now();
LocalDateTime ldtNextMonth = ldtNow.plusMonths(1);

System.out.println("1. " + ldtNow);
System.out.println("2. " + ldtNextMonth);

System.out.println("3. " + ldtNow.atZone(ZoneId.systemDefault()).toInstant().toString());
System.out.println("4. " + ldtNextMonth.atZone(ZoneId.systemDefault()).toInstant().toString());

System.out.println("5. " + ldtNow.atZone(ZoneOffset.systemDefault()).toInstant().toString());
System.out.println("6. " + ldtNextMonth.atZone(ZoneOffset.systemDefault()).toInstant().toString());

This is what it prints:

 1. 2022-10-26T16:53:59.691891
 2. 2022-11-26T16:53:59.691891

 3. 2022-10-26T14:53:59.691891Z
 4. 2022-11-26T15:53:59.691891Z //WRONG?

 5. 2022-10-26T14:53:59.691891Z
 6. 2022-11-26T15:53:59.691891Z //WRONG?

Prints 3. & 4. test it with ZoneId and prints 5. & 6. with ZoneOffset.

The only difference between 3. & 4. (and 5. & 6.) is the usage of LocalDateTime#plusMonths method. What should I do to get right result for zero time (2022-11-26T14:53:59.691891Z)?


Solution

  • The method atZone() returns ZonedDatetime and then you experience the daylight saving effect. Different zones around the globe have daylight saving at different dates.

    So your prints are:

     1. 2022-10-26T16:53:59.691891  // LocalDateTime
     2. 2022-11-26T16:53:59.691891  // LocalDateTime
    
     3. 2022-10-26T14:53:59.691891Z // ZonedDateTime
     4. 2022-11-26T15:53:59.691891Z // ZonedDateTime
    
     5. 2022-10-26T14:53:59.691891Z // ZonedDateTime
     6. 2022-11-26T15:53:59.691891Z // ZonedDateTime  
    

    UTC time zone is like a reference point for any other timezone. For example CET, central european time timezone have the zone offsets of UTC+2 and UTC+1 depending on the period of the year.

    You can see this effect by executing the following snippet:

    ZonedDateTime zdt1 = ldtNow.atZone(ZoneOffset.systemDefault());
    ZonedDateTime zdt2 = ldtNextMonth.atZone(ZoneOffset.systemDefault());
    
    System.out.println(ZoneOffset.from(zdt1));   // prints +02:00
    System.out.println(ZoneOffset.from(zdt2));   // prints +01:00