java 带有 ISO 参数的 DateTimeFormat 不能正确解析时区
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/37110016/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
DateTimeFormat with ISO parameter not parsing timezone correctly
提问by Mathijs Segers
I have this controller which I'm trying to test using mockMVC
我有这个控制器,我正在尝试使用 mockMVC 进行测试
@RequestMapping(value = "/something/{language}", method = RequestMethod.GET, produces = { "application/json", "application/xml" })
public ResponseEntity<someEntity> getInfo(
@PathVariable String language,
@DateTimeFormat(iso= DateTimeFormat.ISO.DATE_TIME) @RequestParam(required = false) Date fromDate
)
So I'm expecting to allow date formats like in docs to be parsable: DATE_TIME The most common ISO DateTime Format yyyy-MM-dd'T'HH:mm:ss.SSSZ, e.g.
所以我希望允许像文档中的日期格式可以解析:DATE_TIME 最常见的 ISO 日期时间格式 yyyy-MM-dd'T'HH:mm:ss.SSSZ,例如
However I keep on getting things like this:
但是我一直在得到这样的东西:
Handler execution resulted in exception: Failed to convert value of type 'java.lang.String' to required type 'java.util.Date'; nested exception is
处理程序执行导致异常:无法将类型“java.lang.String”的值转换为所需类型“java.util.Date”;嵌套异常是
org.springframework.core.convert.ConversionFailedException:
Failed to conv ert from type java.lang.String to type
@org.springframework.format.annotation.DateTimeFormat
@org.springframework.web.bind.annotation.RequestParam java.util.Date for value '2015-09-26T01:30:00.000Z'; nested exception is
java.lang.IllegalArgumentException: Unable to parse '2015-09-26T01:30:00.000Z'
As far as I can see I'm not doing anything wrong, which must be of course. Can anyone shine a light what my bad is? I don't think I need to post more code since the exception does show the correct value which I'm passing to the API right?
据我所知,我没有做错任何事,这当然是肯定的。任何人都可以照亮我的坏处吗?我认为我不需要发布更多代码,因为异常确实显示了我传递给 API 的正确值,对吗?
回答by linuxunil
How it works
怎么运行的
You receive the Date as an String
(HTTP Request is text based) and instruct Spring on how to convert it to an Date Object by a pattern
.
您将日期作为String
(HTTP 请求是基于文本的)接收并指示 Spring 如何通过pattern
.
//Spring controller
@GetMapping
public List<Foobar> find(
@RequestParam(name = "startDate", required = false)
@DateTimeFormat(pattern = "YOUR_DATE_PATTERN" or iso="ISO Enum member") //how to convert the date string
Date startDate {
return service.find(startDate); //work with the java.util.Date object
}
Spring will delegate this task to the java.text.DateTimeFormat
, so the pattern should be a valid one for the formatter class to work with.
Spring 会将这个任务委托给java.text.DateTimeFormat
,因此该模式应该是格式化程序类可以使用的有效模式。
@DateTimeFormat - Pattern VS Iso
@DateTimeFormat - 模式 VS Iso
- Pattern : Specify your pattern. Will be passed directly to the formatter.
- Iso : An member of
org.springframework.format.annotation.DateTimeFormat.ISO
Enum, that has a pre-built Date String Pattern. From the Enum docs:
- 图案:指定您的图案。将直接传递给格式化程序。
- Iso :
org.springframework.format.annotation.DateTimeFormat.ISO
Enum的成员,具有预构建的日期字符串模式。从枚举文档:
DATE The most common ISO Date Format yyyy-MM-dd, e.g.
DATE_TIME The most common ISO DateTime Format yyyy-MM-dd'T'HH:mm:ss.SSSZ, e.g.
NONE Indicates that no ISO-based format pattern should be applied.
TIME The most common ISO Time Format HH:mm:ss.SSSZ, e.g.
DATE 最常见的 ISO 日期格式 yyyy-MM-dd,例如
DATE_TIME 最常见的 ISO 日期时间格式 yyyy-MM-dd'T'HH:mm:ss.SSSZ,例如
NONE 表示不应应用基于 ISO 的格式模式。
TIME 最常见的 ISO 时间格式 HH:mm:ss.SSSZ,例如
- Notice that ALL Enum members (except for NONE), uses 'Z' for the timezone.
- 请注意,所有枚举成员(NONE 除外)都使用“Z”作为时区。
What 'Z' means in the date pattern?
日期模式中的“Z”是什么意思?
Looking at the Javadocs of the Date and Time Patterns, we have two options to handle timezones:
- 'Z' Char : RFC 822 Timezone Syntax (Spring will use this syntax)
查看日期和时间模式的 Javadocs,我们有两个选项来处理时区:
- 'Z' 字符:RFC 822 时区语法(Spring 将使用此语法)
zone = "UT" / "GMT" ; Universal Time ; North American : UT / "EST" / "EDT" ; Eastern: - 5/ - 4 / "CST" / "CDT" ; Central: - 6/ - 5 / "MST" / "MDT" ; Mountain: - 7/ - 6 / "PST" / "PDT" ; Pacific: - 8/ - 7 / 1ALPHA ; Military: Z = UT; ; A:-1; (J not used) ; M:-12; N:+1; Y:+12 / ( ("+" / "-") 4DIGIT ) ; Local differential ; hours+min. (HHMM)
zone = "UT" / "GMT" ; Universal Time ; North American : UT / "EST" / "EDT" ; Eastern: - 5/ - 4 / "CST" / "CDT" ; Central: - 6/ - 5 / "MST" / "MDT" ; Mountain: - 7/ - 6 / "PST" / "PDT" ; Pacific: - 8/ - 7 / 1ALPHA ; Military: Z = UT; ; A:-1; (J not used) ; M:-12; N:+1; Y:+12 / ( ("+" / "-") 4DIGIT ) ; Local differential ; hours+min. (HHMM)
- 'X' Char : ISO 8601 Timezone designators
- 'X' 字符:ISO 8601 时区指示符
Time offsets (15:00?03:30) OR 'Z' for UTC/GMT timezone
UTC/GMT 时区的时间偏移 (15:00?03:30) 或“Z”
The issue
问题
- If you select
org.springframework.format.annotation.DateTimeFormat.ISO.DATE_TIME
Enum member, it will use theyyyy-MM-dd'T'HH:mm:ss.SSSZ
pattern with the RFC 822 syntax for the timezones.
- 如果您选择
org.springframework.format.annotation.DateTimeFormat.ISO.DATE_TIME
Enum 成员,它将使用yyyy-MM-dd'T'HH:mm:ss.SSSZ
具有 RFC 822 语法的时区模式。
The fix
修复
Use the same pattern but with the 'X' for the timezones (use the ISO 8601 syntax) :
yyyy-MM-dd'T'HH:mm:ss.SSSX
使用相同的模式,但时区使用“X”(使用 ISO 8601 语法):
yyyy-MM-dd'T'HH:mm:ss.SSSX
About the Z Timezone
关于 Z 时区
- ISO 8601 states:
- ISO 8601 规定:
Coordinated Universal Time (UTC)
If the time is in UTC, add a Z directly after the time without a space. Z is the zone designator for the zero UTC offset. "09:30 UTC" is therefore represented as "09:30Z" or "0930Z". "14:45:15 UTC" would be "14:45:15Z" or "144515Z".
The Z suffix in the ISO 8601 time representation is sometimes referred to as "Zulu time" because the same letter is used to designate the Zulu time zone. However the ACP 121 standard that defines the list of military time zones makes no mention of UTC and derives the "Zulu time" from the Greenwich Mean Time[27] which was formerly used as the international civil time standard.
协调世界时 (UTC)
如果时间是 UTC,则直接在时间后添加一个 Z,不带空格。Z 是零 UTC 偏移的区域指示符。因此,“09:30 UTC”表示为“09:30Z”或“0930Z”。“14:45:15 UTC”将是“14:45:15Z”或“144515Z”。
ISO 8601 时间表示中的 Z 后缀有时称为“祖鲁时间”,因为相同的字母用于指定祖鲁时区。然而,定义军用时区列表的 ACP 121 标准并未提及 UTC,而是从格林威治标准时间 [27] 派生出“祖鲁时间”,格林威治标准时间 [27] 以前用作国际民用时间标准。
Related Links
相关链接
回答by Sanjeev
As per DateTimeFormat.ISO.DATE_TIME
按照 DateTimeFormat.ISO.DATE_TIME
The most common ISO DateTime Format yyyy-MM-dd'T'HH:mm:ss.SSSZ, e.g. 2000-10-31 01:30:00.000-05:00.
最常见的 ISO 日期时间格式 yyyy-MM-dd'T'HH:mm:ss.SSSZ,例如 2000-10-31 01:30:00.000-05:00。
Where a Z
represents a timezone value for example -05:00.
其中 aZ
表示时区值,例如 -05:00。
Your string value which is unparseable is 2015-09-26T01:30:00.000Z
where Z must be replaced with actual timezone value.
您2015-09-26T01:30:00.000Z
无法解析的字符串值是Z 必须替换为实际时区值的地方。
For example 2015-09-26T01:30:00.000-04:00
will be parsed by ISO.DATE_TIME
correctly
例如2015-09-26T01:30:00.000-04:00
将被ISO.DATE_TIME
正确解析
回答by Francesco
Try notto pass the parameter fromDate
as a String.
尽量不要将参数fromDate
作为字符串传递。
I had the same issue and when I unwrapped the parameter's value from double quotes ("
) in the API call (I used Postman), it worked. You might have to encode some of the characters (i.e. +) though.
我遇到了同样的问题,当我"
在 API 调用(我使用 Postman)中从双引号 ( ) 中解开参数的值时,它起作用了。不过,您可能需要对某些字符(即 +)进行编码。