Search code examples
javaspring-bootlocaldatetime

MessageConversionException occurred when mapping string date to LocalDateTime


I have a queue that listens to a topic and my listener receives a DTO. I need to parse the String to LocalDateTime but I'm getting this error

org.springframework.messaging.converter.MessageConversionException: Could not read JSON: Text '2020-06-18 11:12:46' could not be parsed at index 10

Here is the message details

{"id":444, "details":{"TYPE":[1]},"dateOccurred":"2020-06-18 11:12:46"}"] 

And here is how I set it in my DTO

public class PlanSubscriptionDto {
    private Long id;

    private Map<String, List<Long>> details;

    private LocalDateTime dateOccurred;

    public void setDateOccurred(String dateTime) {
        this.dateOccurred = LocalDateTime.parse(dateTime, DateTimeFormatter.ISO_DATE_TIME);
//ive also tried this
//this.dateOccurred = LocalDateTime.parse(dateTime, DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG));
    }
}

Thank you for your help! Any advice would we great.


Solution

  • Use a format pattern string to define the format.

    public class PlanSubscriptionDto {
        private static final DateTimeFormatter FORMATTER
                = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss");
    
        private Long id;
    
        private Map<String, List<Long>> details;
    
        private LocalDateTime dateOccurred;
    
        public void setDateOccurred(String dateTime) {
            this.dateOccurred = LocalDateTime.parse(dateTime, FORMATTER);
        }
    }
    

    Why didn’t your code work?

    ISO 8601 format has a T between the date and the time. There’s no T in your date-time string, so DateTimeFormatter.ISO_DATE_TIME cannot parse it.

    Variants

    Now we’re at it, I’d like to show a couple of other options. Taste differs, so I can’t tell which one you’ll like the best.

    You may put in the T to obtain ISO 8601 format. Then you will need no explicit formatter. The one-arg LocalDateTime.parse() parses ISO 8601 format.

        public void setDateOccurred(String dateTime) {
            dateTime = dateTime.replace(' ', 'T');
            this.dateOccurred = LocalDateTime.parse(dateTime);
        }
    

    Or sticking to the formatter and the space between date and time, we can define the formatter in this wordier way:

        private static final DateTimeFormatter FORMATTER = new DateTimeFormatterBuilder()
                .append(DateTimeFormatter.ISO_LOCAL_DATE)
                .appendLiteral(' ')
                .append(DateTimeFormatter.ISO_LOCAL_TIME)
                .toFormatter();
    

    What we get for the extra code lines is (1) more reuse of built-in formatters (2) this formatter will accept time without seconds and time with a fraction of second too because DateTimeFormatter.ISO_LOCAL_TIME does.

    Link

    Wikipedia article: ISO 8601