jainilvachhani
jainilvachhani

Reputation: 914

Java ZonedDateTime.parse not working as expected

I am using Java 17. I am trying to parse different strings as ZonedDateTime but when I try to convert it to an Instant, the output is not as expected. For eg:

        String first = "2020-01-08T21:00:00Z[Europe/Berlin]";
        ZonedDateTime zone1 = ZonedDateTime.parse(first);
        String second = "2020-01-08T20:00:00Z[UTC]";
        ZonedDateTime zone2 = ZonedDateTime.parse(second);
        System.out.println(zone1.toInstant());
        System.out.println(zone2.toInstant());

The output is (this is wrong, both times should be same):

2020-01-08T21:00:00Z
2020-01-08T20:00:00Z

However, when I create a ZonedDateTime object using constructor and ZoneId I get correct output:

        ZonedDateTime z1 = ZonedDateTime.of(2020,1,8,21,0,0,0,ZoneId.of("Europe/Berlin"));
        System.out.println(z1.toInstant());
        
        ZonedDateTime z2 = ZonedDateTime.of(2020,1,8,20,0,0,0,ZoneId.of("UTC"));
        System.out.println(z2.toInstant());

Output:

2020-01-08T20:00:00Z
2020-01-08T20:00:00Z

Can anyone tell me why my parse method is not working as expected?

Note: This issue is NOT related to DST bug for ZonedTimeZone in JDK8:

Upvotes: 0

Views: 291

Answers (2)

Sanjay Bharwani
Sanjay Bharwani

Reputation: 4809

You need to parse it and provide the correct format. Below code works for me.

var dateUtcPlus1 = "2025-01-10T17:15:00+01:00"

ZonedDateTime date1 = ZonedDateTime.parse(dateUtcPlus1, DateTimeFormatter.ISO_OFFSET_DATE_TIME).truncatedTo(ChronoUnit.SECONDS);

In fact I have a parameterized unit test to explain the same.

@ParameterizedTest(name = "Date {0} is {2} Date {1}")
    @CsvSource({
        "2025-01-10T17:15:00+01:00,2025-01-10T16:15:00+00:00,EqualTo",
        "2025-01-10T15:15:00+05:00,2025-01-10T10:15:00+00:00,EqualTo",
        "2025-01-10T12:15:00+05:00,2025-01-10T08:15:00+00:00,Before",
        "2025-01-10T15:55:00+05:00,2025-01-10T10:45:00+00:00,After",
    })
    void testEqualTimesInDifferentZonesFromStringFormat(String sourceDate, String targetDate, String expectedResult) {
      ZonedDateTime date1 = ZonedDateTime.parse(sourceDate, DateTimeFormatter.ISO_OFFSET_DATE_TIME).truncatedTo(ChronoUnit.SECONDS);
      ZonedDateTime date2 = ZonedDateTime.parse(targetDate, DateTimeFormatter.ISO_OFFSET_DATE_TIME).truncatedTo(ChronoUnit.SECONDS);

      if ("EqualTo".equals(expectedResult)) {
        assertThat(date1).isEqualTo(date2);
      } else if ("Before".equals(expectedResult)) {
        assertThat(date1.isBefore(date2)).isTrue();
      } else if ("After".equals(expectedResult)) {
        assertThat(date1.isAfter(date2)).isTrue();
      }
    }

Upvotes: 0

Michael Gantman
Michael Gantman

Reputation: 7808

In your input string "2020-01-08T21:00:00Z[Europe/Berlin]" (and the second one) remove 'Z' as that means that it is a UTC time and subsequent timezone is ignored. So, both of your times are in UTC meaning that the first one is NOT in [Europe/Berlin] time zone. You might want to parse the strings using format mask using DateTimeFormatter class. Or replace 'Z' with '+01:00' and then you don't need to use formatting.

Upvotes: 3

Related Questions