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();