I am trying to tell Gson how to parse LocalDateTime
and LocalDate
, but I'm getting this error, which looks to me like it should match the format. I'm thinking there's either something I don't understand about parsing dates or something I don't understand about Gson.
java.time.format.DateTimeParseException: Text '2017101800000700' could not be parsed at index 0
Gson gson = new GsonBuilder().registerTypeAdapter(LocalDateTime.class, new JsonDeserializer<LocalDateTime>() {
@Override
public LocalDateTime deserialize(JsonElement json, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
return LocalDateTime.parse(json.getAsJsonPrimitive().getAsString(), DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS"));
}
}).registerTypeAdapter(LocalDate.class, new JsonDeserializer<LocalDate>() {
@Override
public LocalDate deserialize(JsonElement json, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
return LocalDate.parse(json.getAsJsonPrimitive().getAsString(), DateTimeFormatter.ofPattern("yyyyMMdd"));
}
}).create();
As @Jon Skeet said in the comments, your pattern has 1 extra digit when compared to the input string, so yyyyMMddHHmmssSSS
won't work: the input 2017101800000700
has 16 digits, while the pattern yyyyMMddHHmmssSSS
expects 17.
Although the last part (0700
) looks like an UTC offset, it's missing a +
or -
sign (so it should be +0700
or -0700
). The offset represents the difference from UTC, and without a sign, it's ambiguous: you can't say if it's ahead or behind UTC.
And even if it's really an offset, I couldn't find a way to parse without a sign: I tried with all the available options and none worked. A sign is always required, so parsing it as an offset is not possible, unless you make an arbitrary assumption (such as "it's positive") and change the input manually, like this:
// assuming the offset "0700" is positive (7 hours ahead UTC)
String dateStr = "2017101800000700";
// insert the "+" manually, so input becomes 201710180000+0700
dateStr = dateStr.substring(0, 12) + "+" + dateStr.substring(12, 16);
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyyMMddHHmmXX");
System.out.println(LocalDateTime.parse(dateStr, fmt)); // 2017-10-18T00:00
This will result in a LocalDateTime
equals to:
2017-10-18T00:00
Another alternative is to treat 07
as seconds and the last 2 zeroes as fractions of second.
In this case, a pattern such as yyyyMMddHHmmssSS
won't work due to a bug in Java 8 API.
The same link above also provides the workaround: use a java.time.format.DateTimeFormatterBuilder
with a java.time.temporal.ChronoField
for the fraction of seconds.
String dateStr = "2017101800000700";
DateTimeFormatter fmt = new DateTimeFormatterBuilder()
// date/time
.appendPattern("yyyyMMddHHmmss")
// milliseconds (with 2 digits)
.appendValue(ChronoField.MILLI_OF_SECOND, 2)
// create formatter
.toFormatter();
System.out.println(LocalDateTime.parse(dateStr, fmt)); // 2017-10-18T00:00:07
This will parse the following LocalDateTime
:
2017-10-18T00:00:07
Note that it's different from the previous one, because now we're considering 07
to be the seconds.