Reputation: 7256
I have issue with parsing following date format:
2017-03-27T08:27:43.326TGMT-05:00
I have code where DateTimeFormatter
produces string out of ZonedDateTime
and as a next step I am trying to parse this string again and create ZonedDateTime
instance, however it doesn't work as I expected:
String pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'T'ZZZZ";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
String dateStr = ZonedDateTime.now().format(formatter);
System.out.println(dateStr);
ZonedDateTime dateParsed = ZonedDateTime.parse(dateStr, formatter);
System.out.println(dateParsed);
The code above produces:
2017-03-27T08:27:43.326TGMT-05:00
java.time.format.DateTimeParseException: Text '2017-03-27T08:27:43.326TGMT-05:00' could not be parsed: String index out of range: 33
at java.time.format.DateTimeFormatter.createError(DateTimeFormatter.java:1920)
at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1855)
Looking for any insight on how to come up with working pattern that is capable to create ZonedDateTime
instance out of 2017-03-27T08:27:43.326TGMT-05:00
Upvotes: 3
Views: 1115
Reputation:
To understand what the ZZZZ
pattern does, take a look at the JDK docs, where you can see its meaning:
Pattern Count Equivalent builder methods
------- ----- --------------------------
ZZZZ 4 appendLocalizedOffset(TextStyle.FULL);
So, ZZZZ
is equivalent to appendLocalizedOffset(TextStyle.FULL)
. If you look at appendLocalizedOffset method:
Appends the localized zone offset, such as 'GMT+01:00', to the formatter. This appends a localized zone offset to the builder, the format of the localized offset is controlled by the specified style to this method:
- full - formats with localized offset text, such as 'GMT, 2-digit hour and minute field, optional second field if non-zero, and colon.
And note that it has different behaviours when parsing and formatting:
During formatting, the offset is obtained using a mechanism equivalent to querying the temporal with TemporalQueries.offset(). If the offset cannot be obtained then an exception is thrown unless the section of the formatter is optional.
During parsing, the offset is parsed using the format defined above. If the offset cannot be parsed then an exception is thrown unless the section of the formatter is optional.
So, it seems that ZZZZ
pattern adds the GMT-05:00
when formatting (without the seconds when it's zero), but when parsing, it tries to parse the seconds (even when they're not present).
That's why, when parsing, you need to add :00
in the end (as @freedev did in his answer).
As ZZZZ
seems to be the only pattern that adds GMT
before the offset (all the others just add the offset without GMT
), I think the only solution is to add it by hand. You can do it using java.time.format.DateTimeFormatterBuilder
class:
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
// append the yyyy-MM-dd'T'HH:mm:ss.SSS pattern
.appendPattern("yyyy-MM-dd'T'HH:mm:ss.SSS")
// append "T" and "GMT"
.appendLiteral("TGMT")
// append the offset (-05:00)
.appendOffsetId()
.toFormatter();
With this formatter, your code will work as expected:
String dateStr = ZonedDateTime.now().format(formatter);
System.out.println(dateStr);
ZonedDateTime dateParsed = ZonedDateTime.parse(dateStr, formatter);
System.out.println(dateParsed);
Output:
2017-05-25T08:42:17.799TGMT-05:00
2017-05-25T08:42:17.799-05:00
Testing with your input:
String input = "2017-03-27T08:27:43.326TGMT-05:00";
System.out.println(input);
System.out.println(ZonedDateTime.parse(input, formatter));
Output:
2017-03-27T08:27:43.326TGMT-05:00
2017-03-27T08:27:43.326-05:00
PS: In cases like this I prefer to use a DateTimeFormatterBuilder
, but you can do the same using DateTimeFormatter.ofPattern
directly:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'TGMT'xxx");
This works exactly the same way.
Upvotes: 0
Reputation: 30027
Just for the sake to understand what's wrong I had a look at source code of DateTimeFormatterBuilder.java:3563
where the exception was raised.
I saw there is a piece of code that parse even the seconds parts after GMT-05:00
.
So it will work only if you add the seconds part...
ZonedDateTime dateParsed = ZonedDateTime.parse(dateStr+":00", formatter);
Upvotes: 2