【问题标题】:Custom Pattern for DateTimeFormat Doesn't WorkDateTimeFormat 的自定义模式不起作用
【发布时间】:2021-03-14 14:04:31
【问题描述】:

我有一个带有请求参数的 Rest Controller:

@RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") ZonedDateTime startDate

当我将数据发布到我的控制器时:

startDate=2020-12-02T18:07:33.251Z

但是我收到 400 Bad Request 错误:

2020-12-02 18:20:32.428  WARN 26384 --- [nio-2000-exec-3] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'java.time.ZonedDateTime'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [@org.springframework.web.bind.annotation.RequestParam @org.springframework.format.annotation.DateTimeFormat java.time.ZonedDateTime] for value '2020-12-02T18:07:33.251Z'; nested exception is java.lang.IllegalArgumentException: Parse attempt failed for value [2020-12-02T18:07:33.251Z]]

【问题讨论】:

  • 对不起,'Z'不见了,应该这么简单吗……
  • @Turo 这是一个错字。
  • 'T' 这些引号是干什么用的?
  • @fukanchik ISO 8601 定义以“T”分隔的日期和时间。
  • @kamaci 我又看了一遍,在 ISO 8601 中 T 周围没有 ' 引号。

标签: java spring spring-boot zoneddatetime


【解决方案1】:

您的日期时间字符串 2020-12-02T18:07:33.251Z 已采用 ZonedDateTime#parse 使用的默认格式。

演示:

import java.time.ZonedDateTime;

public class Main {
    public static void main(String args[]) {
        String strDateTime = "2020-12-02T18:07:33.251Z";
        ZonedDateTime zdt = ZonedDateTime.parse(strDateTime);
        System.out.println(zdt);
    }
}

输出:

2020-12-02T18:07:33.251Z

表示可以指定格式,DateTimeFormatter.ISO_ZONED_DATE_TIME,这是ZonedDateTime#parse使用的默认格式。将注释更改为

@RequestParam(required = false) @DateTimeFormat(pattern = DateTimeFormatter.ISO_ZONED_DATE_TIME) ZonedDateTime startDate

@RequestParam(required = false) @DateTimeFormat(iso = ISO.DATE_TIME) ZonedDateTime startDate

查看Spring documentation page 以了解有关第二个选项的更多信息。


其他一些重要说明:

  1. 在任何情况下,都不要在Z 周围加上单引号,它代表Zulu 并表示UTC 的日期时间(区域偏移为+00:00 小时);相反,请使用 X 进行区域偏移。

演示:

import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;

public class Main {
    public static void main(String args[]) {
        String strDateTime = "2020-12-02T18:07:33.251Z";
        ZonedDateTime zdt = ZonedDateTime.parse(strDateTime, DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSX"));
        System.out.println(zdt);
    }
}

输出:

2020-12-02T18:07:33.251Z

查看DateTimeFormatter 了解更多信息。

  1. 此模式对SimpleDateFormat 也有效。

演示:

import java.text.ParseException;
import java.text.SimpleDateFormat;

public class Main {
    public static void main(String args[]) throws ParseException {
        String strDateTime = "2020-12-02T18:07:33.251Z";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX");
        System.out.println(sdf.parse(strDateTime));
    }
}

但是,java.util 的日期时间 API 及其格式 API SimpleDateFormat 已过时且容易出错。建议完全停止使用,转用modern date-time API

【讨论】:

  • 不起作用。似乎问题与此有关: DateTimeFormat#pattern -> 此模式遵循原始的 java.text.SimpleDateFormat 样式,Joda-Time 也支持,对溢出具有严格的解析语义(例如,拒绝非 2 月 29 日的值闰年)。
  • 你的意思是“yyyy-MM-dd'T'HH:mm:ss.SSSXXX”吗?
  • @kamaci - 我已经提到 yyyy-MM-dd'T'HH:mm:ss.SSSX 作为模式。
  • 我仍然得到异常:2020-12-02 23:16:18.796 WARN 28932 --- [nio-2000-exec-9] .wsmsDefaultHandlerExceptionResolver : 已解决 [org.springframework.web. method.annotation.MethodArgumentTypeMismatchException:无法将“java.lang.String”类型的值转换为所需的“java.time.ZonedDateTime”类型;
  • @kamaci - 试试iso = ISO.DATE_TIME。我已经更新了我的答案以包含此选项。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多