Jim
Jim

Reputation: 16002

custom deserializing a date with format

["last_modified"])] with root cause java.time.format.DateTimeParseException: Text '2018-06-06T13:19:53+00:00' could not be parsed, unparsed text found at index 19

The inbound format is 2018-06-06T13:19:53+00:00
It's a weird format.

I have tried the following:

public class XYZ {  
    @DateTimeFormat(pattern = "yyyy-MM-ddTHH:mm:ss+00:00", iso = ISO.DATE_TIME)
    private LocalDateTime lastModified;
}  

Upvotes: 4

Views: 3029

Answers (3)

cassiomolin
cassiomolin

Reputation: 130837

The inbound format is 2018-06-06T13:19:53+00:00
It's a weird format.

That's the ISO 8601 format, which is endorsed by the RFC 3339 and by the xkcd 1179:

xkcd 1179: ISO 8601


The following should work as expected when receiving the values as query parameters:

@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
private LocalDate dateTime;

As 2018-06-06T13:19:53+00:00 represents a date and time with an offset from UTC, you'd better use OffsetDateTime rather than LocalDateTime:

@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
private OffsetDateTime dateTime;

Just ensure that + is encoded as %2B.


With Jackson, you could add the jackson-datatype-jsr310 dependency to your application. This module will provide you with serializers and deserializers for java.time types.

<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jsr310</artifactId>
    <version>${jackson.version}</version>
</dependency>

And then register the JavaTimeModule module in your ObjectMapper:

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);

Jackson will handle the serialization and deserialization for you.

If you are, for some reason, not interested in the offset from UTC and want to keep using LocalDateTime, you could extend the LocalDateTimeDeserializer provided by Jackson and use a custom DateTimeFormatter:

public class CustomLocalDateTimeDeserializer extends LocalDateTimeDeserializer {

    public CustomLocalDateTimeDeserializer() {
        super(DateTimeFormatter.ISO_OFFSET_DATE_TIME);
    }
}

Then annotate the LocalDateTime field as shown below:

@JsonDeserialize(using = CustomLocalDateTimeDeserializer.class)
private LocalDateTime dateTime;

Upvotes: 1

Mark
Mark

Reputation: 525

The inbound format is 2018-06-06T13:19:53+00:00

If you're able to set the Date Format on your entire ObjectMapper, you could do the following:

DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
objectMapper.setDateFormat(df);

This is part of the examples from the SimpleDateFormat Javadocs

Upvotes: 0

akourt
akourt

Reputation: 5563

There is nothing stopping you from creating your own deserializer. A very naive example could be the following:

public class LocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {

    private static final String PATTERN = "yyyy-MM-dd'T'HH:mm:ss+00:00";

    private final DateTimeFormatter formatter;

    public LocalDateTimeDeserializer() {
        this.formatter = DateTimeFormatter.ofPattern(PATTERN);
    }

    @Override
    public LocalDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        return LocalDateTime.parse(p.getText(), formatter);
    }
}

The only thing you need to notice is that you'll need to escape the 'T' by adding single quote around it.

With the deserializer in place you can simply annotate the field like so:

@JsonDeserialize(using = LocalDateTimeDeserializer.class)
private LocalDateTime dateTime;

Upvotes: 5

Related Questions