Search code examples
javajava-timezoneddatetime

behavior of ZonedDateTime when parsing string with conflicting zone id and offset


I could not find what the expected behavior is when parsing a string with a conflicting zone id and offset.

For example:

ZonedDateTime d = ZonedDateTime.parse("2015-06-17T12:55:33+05:00[Europe/Amsterdam]");
println(d.toString()); // prints 2015-06-17T12:55:33+02:00[Europe/Amsterdam]

In this case parse() seems to ignore the incorrect offset of +05:00 and uses the offset determined by the zone ID (Europe/Amsterdam)

As the documentation says:

The offset cannot be freely set, as the zone controls which offsets are valid.

I would have expected parse() throwing an exception because +05:00 is an invalid offset for zone Europe/Amsterdam. What is the correct behavior in this case?


Solution

  • The parsing implicitly calls the static from(TemporalAccessor)-method of ZonedDateTime. Its documentation says:

    The conversion will first obtain a ZoneId from the temporal object, falling back to a ZoneOffset if necessary.

    This supports the observation that the zone-id is preferred compared with the offset information. If you explicitly use strict mode then I would - like you - expect an exception:

    DateTimeFormatter dtf = 
      new DateTimeFormatterBuilder()
      .parseStrict()
      .appendPattern("uuuu-MM-dd'T'HH:mm:ssXXX'['VV']'").toFormatter();
    ZonedDateTime d = ZonedDateTime.parse("2015-06-17T12:55:33+05:00[Europe/Amsterdam]", dtf);
    System.out.println(d.toString()); // 2015-06-17T12:55:33+02:00[Europe/Amsterdam]
    

    No exception is observed however. And the parse(String)-method is documented to use ISO_ZONED_DATE_TIME (also tested by me with the same result) which is defined to be strict, too. Maybe you can file an issue to Oracle. It is up to them to decide what they consider as "correct behaviour" that is if they consider this behaviour as undocumented feature or as bug.

    Personally I consider it as bug because for example the expression LocalDate.parse("Friday, 2016-03-08", new DateTimeFormatterBuilder().parseLenient().appendPattern("EEEE, uuuu-MM-dd").toFormatter().withLocale(Locale.ENGLISH)) indeed produces an exception due to ambivalent (weekday)-informations - even in lenient-mode (which is also not so good).


    For comparison: In my time library Time4J, I have implemented such a check if the offset information is consistent.

    ChronoFormatter<Moment> cf = 
        ChronoFormatter.ofMomentPattern("uuuu-MM-dd'T'HH:mm:ssXXX'['VV']'", PatternType.CLDR, Locale.ROOT, ZonalOffset.UTC);
    System.out.println(cf.with(Leniency.STRICT).parse("2015-06-17T12:55:33+05:00[Europe/Amsterdam]"));
    // Exception in thread "main" java.text.ParseException: Ambivalent offset information: AMSTERDAM versus +05:00
    
    // this alternative formatter can be used as workaround for strict parsing
    ZonedDateTime zdt = 
      ZonalDateTime.parse(
        "2015-06-17T12:55:33+05:00[Europe/Amsterdam]", 
        cf.with(Leniency.STRICT)
      ).toTemporalAccessor();