Basil Bourque Basil Bourque - 2 months ago 13
Java Question

Why does `GMT+8` fail to parse with pattern `O` despite being copied straight out of doc?

Why does the following fail to run, with the date-time string unable to parse as an

?

String inputOdt = "2016-01-23T12:34:56 GMT+8";
DateTimeFormatter formatterOdt = DateTimeFormatter.ofPattern ( "yyyy-MM-dd'T'HH:mm:ss O" );
OffsetDateTime odt = OffsetDateTime.parse ( inputOdt , formatterOdt );


Using
Java(TM) SE Runtime Environment (build 1.8.0_92-b14)
on Mac OS X El Capitan 10.11.4.

Generates error:


Exception in thread "main" java.time.format.DateTimeParseException: Text '2016-01-23T12:34:56 GMT+8' could not be parsed: String index out of range: 25


The offset-from-UTC string
GMT+8
is copied-pasted from the example in the class documentation for
DateTimeFormatter
. To quote:


Offset O: This formats the localized offset based on the number of pattern letters. One letter outputs the short form of the localized offset, which is localized offset text, such as 'GMT', with hour without leading zero, optional 2-digit minute and second if non-zero, and colon, for example 'GMT+8'.





The rest of the string parses successfully as a
LocalDateTime
. So the problem seems to indeed be the offset-from-UTC part.

String inputLdt = "2016-01-23T12:34:56";
DateTimeFormatter formatterLdt = DateTimeFormatter.ofPattern ( "yyyy-MM-dd'T'HH:mm:ss" );
LocalDateTime ldt = LocalDateTime.parse ( inputLdt , formatterLdt );

System.out.println ( "" );
System.out.println ( "inputLdt: " + inputLdt );
System.out.println ( "ldt: " + ldt );



inputLdt: 2016-01-23T12:34:56

ldt: 2016-01-23T12:34:56





Workaround



A partial workaround is to add a trailing SPACE to both the input string and the formatting pattern. So this works.

String input = "Sat May 02 2015 00:00:00 GMT+08 "; // Trailing space.
DateTimeFormatter formatter = DateTimeFormatter.ofPattern ( "EEE MMM dd yyyy HH:mm:ss O " ); // Trailing space.
OffsetDateTime odt = OffsetDateTime.parse ( input , formatter ); // SUCCEEDS


But adding minutes without a colon is documented as working with a single
O
but it fails. This workaround of a trailing SPACE does not help in such a case. Notice the
GMT+0800
in this example versus
GMT+08
seen directly above, where this example fails but the one above succeeds.

String input = "Sat May 02 2015 00:00:00 GMT+0800 "; // Minutes in the offset, and trailing space.
DateTimeFormatter formatter = DateTimeFormatter.ofPattern ( "EEE MMM dd yyyy HH:mm:ss O " ); // Trailing space.
OffsetDateTime odt = OffsetDateTime.parse ( input , formatter ); // FAILS

Answer

Seems to be a bug in Java. See https://bugs.openjdk.java.net/browse/JDK-8154050:

java.time.format.DateTimeFormatter can't parse localized zone-offset

The DateTimeFormatter fails to parse its own output for format strings containing "O". The following code throws a StringIndexOutOfBoundsException on the final line.

import java.time.ZoneOffset
import java.time.ZonedDateTime
import java.time.format.DateTimeFormatter
DateTimeFormatter formatter = DateTimeFormatter
        .ofPattern("yyyy-MM-dd'T'HH:mm:ss.S O")
        .withLocale(Locale.ENGLISH)
String date = formatter.format(ZonedDateTime.now(ZoneOffset.UTC));
formatter.parse(date)

ERROR MESSAGES/STACK TRACES THAT OCCUR : java.time.format.DateTimeParseException: Text '2016-04-08T10:49:52.7 GMT' could not be parsed: String index out of range: 25

And in a comment:

Attached test case executed on:
JDK 8 - Fail
JDK 8u77 - Fail
JDK 9EA - Fail

Seems it was fixed in Java 9 build b116.