config:

format:
  date-time: yyyy-MM-dd HH:mm:ss
  date: yyyy-MM-dd
  time: HH:mm:ss

code:

public record TestParam(Date updateTime){
}
@GetMapping("/test")
public void list(TestParam bo) {
    System.out.println("rec: " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(bo.updateTime()));
}

request: url param updateTime: 2024-07-18 02:00:10

GET http://localhost/test?updateTime=2024-07-18%2002%3A00%3A10

Current Output:

rec: 2024-07-18 00:00:00

Expected Output:

rec: 2024-07-18 02:00:10

With the same configuration, using the LocalDateTime class to receive parameters results in successful conversion.

I took a quick look at the code, and it seems that the String to Date converter only utilizes the spring.mvc.format.date configuration and ignores the spring.mvc.format.time and spring.mvc.format.date-time configurations.

Comment From: relufi

https://github.com/spring-projects/spring-boot/blob/c693b2bd8cfa7c10b2791aea58f26d55be548c33/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/format/WebConversionService.java#L93-L101

In the registerJavaDate method, the converter configuration only reads the spring.mvc.format.date setting, causing it to convert only the date portion and ignore the time portion when converting time strings.

Comment From: relufi

https://github.com/spring-projects/spring-boot/blob/c693b2bd8cfa7c10b2791aea58f26d55be548c33/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/format/DateTimeFormatters.java#L46-L78

Remove this.datePattern = pattern; from dateFormat method and put it into dateTimeFormat method. In this way, the converter can obtain the pattern configured in spring.mvc.format.date-time to fully parse the time.

Comment From: dstanwar17

It seems the registerJavaDate method only uses spring.mvc.format.date, missing the time portion. Also, moving this.datePattern = pattern from dateFormat to dateTimeFormat in DateTimeFormatters might help the converter use the spring.mvc.format.date-time configuration properly. Can I give it a try?

Comment From: wilkinsona

Thanks for the report, @relufi.

I think the crux of the problem is that java.util.Date is being treated as something that only provides a date when it actually provides a date and a time. As such, we should be using a date-time pattern to create the DateFormatter that's registered in registerJavaDate.

Unfortunately, we may have users that are relying upon the current behavior and, as far as I can tell, changing it in a backwards compatible way is not straightforward. For example, if someone has set spring.mvc.format.date to yyyy-MM-dd and spring.mvc.format.date-time to iso and we start applying the latter to the java.lang.String -> java.util.Date conversion, an input of 2024-07-15 will no longer parse.

I'll discuss this with the team, but in the meantime I would use LocalDateTime rather than java.util.Date. That's generally recommended anyway as the java.time APIs address many of the limitations of java.util.Date.

Comment From: wilkinsona

We discussed this today and concluded that the best we can do is to document to which types each property applies in its description. The spring.mvc.format.date property has existed for 7 years (since Spring Boot 2.0) making the risk of regression should we change it too high.