Why does the JDK8 DateTime library seem to not parse valid iso8601 date time strings? It chokes on time zone offsets expressed like "+01" instead of "+01:00"
This works:
java.time.ZonedDateTime.parse("2015-08-18T00:00+01:00")
This throws a parse exception:
java.time.ZonedDateTime.parse("2015-08-18T00:00+01")
From the iso8601 wikipedia page:
The offset from UTC is appended to the time in the same way that 'Z' was above, in the form ±[hh]:[mm], ±[hh][mm], or ±[hh]. So if the time being described is one hour ahead of UTC (such as the time in Berlin during the winter), the zone designator would be "+01:00", "+0100", or simply "+01".
EDIT: This looks like an actual legitimate bug in the JDK.
https://bugs.openjdk.java.net/browse/JDK-8032051
Wow, after testing that new date time stuff for years, I thought they would have caught something so obvious. I also thought the JDK author types were rigorous enough to use a better automated test suite.
UPDATE: This is completely fixed in the current jdk-9 build. I just confirmed. The exact same parse command showed above fails in the current jdk-8 build and works perfectly in jdk-9.
ADDENDUM: FWIW, RFC 3339 based on ISO-8601, does not allow for this short hand. You must specify minutes in the time zone offsets.
You use this default formatter: ISO_OFFSET_DATE_TIME (because parse 2015-08-18T00:00+01:00
).
In documentation:
This returns an immutable formatter capable of formatting and parsing the ISO-8601 extended offset date-time format. [...]
The offset ID. If the offset has seconds then they will be handled even though this is not part of the ISO-8601 standard. Parsing is case insensitive.
It's (you use only this for this default formatter):
The ID is minor variation to the standard ISO-8601 formatted string for the offset. There are three formats:
- Z - for UTC (ISO-8601)
- +hh:mm or -hh:mm - if the seconds are zero (ISO-8601)
- +hh:mm:ss or -hh:mm:ss - if the seconds are non-zero (not ISO-8601) (don't
+hh
like ISO-8601).
It seems like java.time (JDK 8) don't full implements ISO-8601 in all.
This:
java.time.ZonedDateTime.parse("2015-08-18T00:00+01:00"); // works
corresponds to (roughly from source JDK):
DateTimeFormatterBuilder builder = new DateTimeFormatterBuilder();
DateTimeFormatter formatter = builder
.parseCaseInsensitive()
.append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
.appendOffsetId()
.toFormatter();
java.time.ZonedDateTime.parse("2015-08-18T00:00+01:00", formatter); // it's same
You can create own DataTimeFormatter with DateTimeFormatterBuilder.
DateTimeFormatterBuilder builder2 = new DateTimeFormatterBuilder();
DateTimeFormatter formatter2 = builder2.parseCaseInsensitive()
.append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
.appendPattern("X") // eg.:
.toFormatter();
java.time.ZonedDateTime.parse("2015-08-18T00:00+01", formatter2); // here you set +01
Instead of appendOffsetId() use appendPattern(String pattern) and set 'X' or 'x'.
Now, you can use your datatime 2015-08-18T00:00+01
.
Or... Use default ISO_OFFSET_DATE_TIME and add postfix :00
.
java.time.ZonedDateTime.parse("2015-08-18T00:00+01" + ":00");
But this last is bad solution.