Generic Top

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE

1. Introduction

In this short tutorial, we’ll take a look at how to accept Date, LocalDate and LocalDateTime parameters in Spring REST requests, both at the request and application levels.

2. The Problem

Let’s consider a controller with three methods that accept Date, LocalDate and LocalDateTime parameters:

@RestController
public class DateTimeController {

    @PostMapping("/date")
    public void date(@RequestParam("date") Date date) {
        // ...
    }

    @PostMapping("/localdate")
    public void localDate(@RequestParam("localDate") LocalDate localDate) {
        // ...
    }

    @PostMapping("/localdatetime")
    public void dateTime(@RequestParam("localDateTime") LocalDateTime localDateTime) {
        // ...
    }
}

When sending a POST request to any of those methods with a parameter formatted in accordance with ISO 8601 we’ll get an exception.

For example, when sending “2018-10-22” to the /date endpoint we will get a bad request error with a message similar to this:

Failed to convert value of type 'java.lang.String' to required type 'java.time.LocalDate'; 
  nested exception is org.springframework.core.convert.ConversionFailedException.

This is because Spring by default cannot convert String parameters to any date or time object.

3. Convert Date Parameters on Request Level

One of the ways to handle this problem is to annotate the parameters with the @DateTimeFormat annotation and provide a formatting pattern parameter:

@RestController
public class DateTimeController {

    @PostMapping("/date")
    public void date(@RequestParam("date") 
      @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) Date date) {
        // ...
    }

    @PostMapping("/local-date")
    public void localDate(@RequestParam("localDate") 
      @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate localDate) {
        // ...
    }

    @PostMapping("/local-date-time")
    public void dateTime(@RequestParam("localDateTime") 
      @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime localDateTime) {
        // ...
    }
}

This way, the Strings will be properly converted to date objects, provided the Strings are formatted using the ISO 8601 format.

We can also use our own conversion patterns. We can just provide a pattern parameter in the @DateTimeFormat annotation:

@PostMapping("/date")
public void date(@RequestParam("date") 
  @DateTimeFormat(pattern = "dd.MM.yyyy") Date date) {
    // ...
}

4. Convert Date Parameters at the Application Level

Another way to handle date and time object conversion in Spring is to provide a global configuration. We can do it by following the official documentation:

@Configuration
class DateTimeConfig {

    @Bean
    public FormattingConversionService conversionService() {
        DefaultFormattingConversionService conversionService = 
          new DefaultFormattingConversionService(false);

        DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar();
        registrar.setDateFormatter(DateTimeFormatter.ofPattern("dd.MM.yyyy"));
        registrar.setDateTimeFormatter(DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm:ss"));
        registrar.registerFormatters(conversionService);

        // other desired formatters

        return conversionService;
    }
}

First, we create DefaultFormattingConversionService with a false parameter, which means Spring will not register any formatters by default.

And then, we manually register new patterns for date and date-time formats in the DateTimeFormatterRegistrar object.

5. Summary

In this article, we’ve learned how to accept the date parameters in Spring MVC requests. We’ve covered how to do it per request and globally.

We’ve also learned how to create our own date formatting patterns.

As always all source code is available over on GitHub.

Generic bottom

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE

newest oldest most voted
Notify of
Alex
Guest
Alex

The global register a custom formatter will cause custom converter(implement of Converter interface) invalid. Any idea to resolve that?
Why Spring won’t use the ISO as default? I think the SS style format, the default one, is an American standard, not international.

Loredana Crusoveanu
Editor

Hey Alex,

If you use this global configuration, you should register all the converters you want here, including the custom one. You can use the conversionService.addConverter() method.

Cheers.