I'm trying to create a DateTimeFormatter
to match the following example (it's actually slightly more complex than this but that shouldn't matter).
20180302-17:45:21
I've written the following but it results in an exception:
new DateTimeFormatterBuilder()
.append(DateTimeFormatter.BASIC_ISO_DATE)
.appendLiteral('-')
.append(DateTimeFormatter.ISO_LOCAL_TIME)
.toFormatter()
.parse("20180302-17:45:21");
The exception is:
Exception in thread "main" java.time.format.DateTimeParseException: Text '20180302-17:45:21' could not be parsed at index 11
at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:1988)
at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1816)
It appears to be failing on the colon between 17:45
and DateTimeFormatterBuilder.appendLiteral
doesn't give any clues.
If I change the literal to another character, let's say m
, then it works fine:
new DateTimeFormatterBuilder()
.append(DateTimeFormatter.BASIC_ISO_DATE)
.appendLiteral('m')
.append(DateTimeFormatter.ISO_LOCAL_TIME)
.toFormatter()
.parse("20180302m17:45:21");
What's going on here? How can I fix it, assuming I can't change the format?
Comments suggest this might be version dependent. I'm using JDK 9.0.1 and it's been reproduced on 9.0.4.
LocalTime. Represents a time (hour, minute, second and nanoseconds (HH-mm-ss-ns)) LocalDateTime. Represents both a date and a time (yyyy-MM-dd-HH-mm-ss-ns) DateTimeFormatter.
static DateTimeFormatter. ISO_DATE_TIME. The ISO-like date-time formatter that formats or parses a date-time with the offset and zone if available, such as '2011-12-03T10:15:30', '2011-12-03T10:15:30+01:00' or '2011-12-03T10:15:30+01:00[Europe/Paris]'.
The DateTimeFormatter class is used to both parse and format dates according to specified Date and Time Patterns. Use parse(...) method to convert from String to Date/Time classes, use format(...) method to convert from Date/Time into String.
DateTimeFormatter is immutable and thread-safe. DateTimeFormatter formats a date-time using user defined format such as "yyyy-MMM-dd hh:mm:ss" or using predefined constants such as ISO_LOCAL_DATE_TIME. A DateTimeFormatter can be created with desired Locale, Chronology, ZoneId, and DecimalStyle.
This has got to do with the fact that DateTimeFormatter.BASIC_ISO_DATE
includes an optional offset ID. Apparently your formatter parses -17
as an offset and then objects because there is a colon where the format requires a hyphen.
When you use m
instead, this cannot be parsed as an offset and therefore matches the literal m
in the format, and everything works.
I tried using uppercase Z
. Z
can be an offset ID too.
new DateTimeFormatterBuilder()
.append(DateTimeFormatter.BASIC_ISO_DATE)
.appendLiteral('Z')
.append(DateTimeFormatter.ISO_LOCAL_TIME)
.toFormatter()
.parse("20180302Z17:45:21");
Now I got java.time.format.DateTimeParseException: Text '20180302Z17:45:21' could not be parsed at index 9
. Index 9 us right after the Z
, so it seems the formatter parses the offset and then tries to find the literal Z
where the 17
is.
EDIT: And the solution? Instead of using BASIC_ISO_DATE
append a pattern:
.appendPattern("uuuuMMdd")
Now parsing works also on Java 9.0.4.
EDIT: Further to illustrate the optionality of the offset:
System.out.println(
LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE)
);
System.out.println(
OffsetDateTime.now().format(DateTimeFormatter.BASIC_ISO_DATE)
);
This printed
20180305
20180305+0100
So in the first case, where no offset is available, it just leaves it out. In the second case, where one is available, it is also printed (without colon).
Open question: Why does it work in Java 8? Is this really a bug?
Quote:
- If the offset is not available to format or parse then the format is complete.
- The offset ID without colons. If the offset has seconds then they will be handled even though this is not part of the ISO-8601 standard. The offset parsing is lenient, which allows the minutes and seconds to be optional. Parsing is case insensitive.
From the documentation of BASIC_ISO_DATE
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With