[英]Java 8 DateTimeFormatter rejects correct ISO 8601 date/time with offset
I use format string for DateTimeFormatter: uuuu-MM-dd'T'HH:mm:ssX 我使用DateTimeFormatter的格式字符串:uuuu-MM-dd'T'HH:mm:ssX
which must support all possible formats of timezone offset, including: Z, 00, 00:00, 0000 必须支持所有可能的时区偏移格式,包括:Z,00,00:00,0000
According to official DateTimeFormatter documentation, 'X' qualifier must match to offset in these formats: 根据官方的DateTimeFormatter文档,'X'限定符必须与这些格式的偏移匹配:
X zone-offset 'Z' for zero offset-X Z; X区偏移'Z'表示零偏移-X Z; -08;
-08; -0830;
-0830; -08:30;
-08:30; -083015;
-083015; -08:30:15;
-08:30:15;
but in fact, it doesn't 但事实上,事实并非如此
input string : "2014-01-01T00:30:00+00:00" 输入字符串 :“2014-01-01T00:30:00 + 00:00”
result : java.time.format.DateTimeParseException: Text '2014-01-01T00:30:00+00:00' could not be parsed, unparsed text found at index 22 result : java.time.format.DateTimeParseException:无法解析文本'2014-01-01T00:30:00 + 00:00',在索引22处找到未解析的文本
input string : "2014-01-01T00:30:00Z" 输入字符串 :“2014-01-01T00:30:00Z”
result : correct 结果 : 正确
the code: 编码:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ssX");
OffsetDateTime parsed = OffsetDateTime.parse(dateTimeAsString, formatter);
JDK 1.8.0_192 (Oracle, not OpenJDK) JDK 1.8.0_192(Oracle,而不是OpenJDK)
This is a little bit complicated. 这有点复杂。 As jvdmr says , the count of Xs matters.
正如jvdmr所说 ,X的数量很重要。
XXXXX
will recognize -08:30:15
, but not -083015
. XXXXX
将识别-08:30:15
,但不是-083015
。 XXXX
will recognize the latter, but not the former. XXXX
将承认后者,但不承认前者。
To take all possible example formats into account, we need to specify different possibilities. 为了考虑所有可能的示例格式,我们需要指定不同的可能性。 This can be done within the format pattern string using square brackets.
这可以使用方括号在格式模式字符串中完成。 These enclose optional parts.
这些包含可选部件。 A little experimentation showed that the following pattern covers all examples:
一些实验表明,以下模式涵盖了所有示例:
uuuu-MM-dd'T'HH:mm:ss[XXXXX][XXXX][X]
Let's try it out: 我们来试试吧:
DateTimeFormatter formatter
= DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss[XXXXX][XXXX][X]");
for (String dts : new String[] {
"2014-01-01T00:30:00-08:30:15", "2014-01-01T00:30:00-083015",
"2014-01-01T00:30:00-08:30", "2014-01-01T00:30:00-0830",
"2014-01-01T00:30:00-08", "2014-01-01T00:30:00Z",
}) {
System.out.println(OffsetDateTime.parse(dts, formatter));
}
Output from this snippet is: 此代码段的输出是:
2014-01-01T00:30-08:30:15 2014-01-01T00:30-08:30:15 2014-01-01T00:30-08:30 2014-01-01T00:30-08:30 2014-01-01T00:30-08:00 2014-01-01T00:30Z
Edit 编辑
VelNaga suggests not to hardcode ISO date-time formats. VelNaga建议不要对ISO日期时间格式进行硬编码。 Since writing format pattern strings is error-prone, this can be a good idea.
由于编写格式模式字符串容易出错,因此这可能是一个好主意。 For example:
例如:
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
.appendPattern("[XXXXX][XXXX][X]")
.toFormatter();
Output using this formatter is the same as with using the one above. 使用此格式化程序的输出与使用上述格式化程序的输出相同。 It's wordier, but we could easily end up thinking that it's worth it since it is less error-prone and may be clearer and easier to read.
它更啰嗦,但我们很容易认为这是值得的,因为它不易出错,可能更清晰,更容易阅读。
From the docs (emphasis mine) : 从文档 (强调我的) :
Offset X and x: This formats the offset based on the number of pattern letters.
偏移X和x: 根据模式字母的数量格式化偏移。 One letter outputs just the hour, such as '+01', unless the minute is non-zero in which case the minute is also output, such as '+0130'.
一个字母仅输出小时,例如'+01',除非分钟非零,在这种情况下分钟也输出,例如'+0130'。 Two letters outputs the hour and minute, without a colon, such as '+0130'.
两个字母输出小时和分钟,没有冒号,例如'+0130'。 Three letters outputs the hour and minute, with a colon, such as '+01:30'.
三个字母输出小时和分钟,带有冒号,例如'+01:30'。 Four letters outputs the hour and minute and optional second, without a colon, such as '+013015'.
四个字母输出小时和分钟以及可选秒,没有冒号,例如'+013015'。 Five letters outputs the hour and minute and optional second, with a colon, such as '+01:30:15'.
五个字母输出小时和分钟,可选秒输出冒号,例如'+01:30:15'。 Six or more letters throws IllegalArgumentException.
六个或更多字母抛出IllegalArgumentException。 Pattern letter 'X' (upper case) will output 'Z' when the offset to be output would be zero, whereas pattern letter 'x' (lower case) will output '+00', '+0000', or '+00:00'.
当要输出的偏移量为零时,模式字母“X”(大写)将输出“Z”,而模式字母“x”(小写)将输出“+00”,“+ 0000”或“+00” :00' 。
This also works in reverse for parsing dates. 这也适用于解析日期。 You want to parse both with and without colons, which means you'll have to use optional sections as no single pattern supports this.
您想要使用和不使用冒号进行解析,这意味着您必须使用可选节,因为没有单个模式支持此选项。 Try this pattern:
"uuuu-MM-dd'T'HH:mm:ss[XXX][XXXX]"
尝试这种模式:
"uuuu-MM-dd'T'HH:mm:ss[XXX][XXXX]"
Don't hardcode any ISO date format. 不要硬编码任何ISO日期格式。 DateFormatter already has a static method for ISO date format conversion.
DateFormatter已经有一个ISO日期格式转换的静态方法。 Use the below code,
使用以下代码,
DateTimeFormatter formatter = DateTimeFormatter.ISO_ZONED_DATE_TIME;
DateTimeFormatter formatter = DateTimeFormatter.ISO_ZONED_DATE_TIME;
OffsetDateTime parsed = OffsetDateTime.parse(dateTimeAsString, formatter);
OffsetDateTime parsed = OffsetDateTime.parse(dateTimeAsString,formatter);
It will work for sure. 它肯定会起作用。 Please find this link for more formatter options.
请在此链接中找到更多格式化程序选项。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.