简体   繁体   English

Java 8 DateTimeFormatter使用偏移拒绝正确的ISO 8601日期/时间

[英]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 resultjava.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.

相关问题 DateTimeFormatter中的格式化程序,用于时间的ISO 8601日期格式 - Formatter in DateTimeFormatter for ISO 8601 date format of the time Java DateTimeFormatter.ISO_OFFSET_DATE_TIME 在 Java 9+ 中返回与 Java 8 不同的值 - Java DateTimeFormatter.ISO_OFFSET_DATE_TIME Returns different values in Java 9+ compared to Java 8 DateTimeFormatter.ISO_OFFSET_DATE_TIME 的等效格式字符串是什么? - What is the equivalent format string of DateTimeFormatter.ISO_OFFSET_DATE_TIME? DateTimeFormatter 和 ISO 8601 字符串 - DateTimeFormatter and ISO 8601 Strings 带区域偏移量的 ISO 8601 日期时间字符串的通用 DateTimeFormatter 模式 - Generic DateTimeFormatter pattern for ISO 8601 datetime string with zone offset Java将ISO 8601字符串转换为忽略偏移量的日期 - Java convert ISO 8601 string to Date ignoring offset 使用java.time.DateTimeFormatter格式化Java日期,包括时间偏移 - Formating java Date with java.time.DateTimeFormatter including time offset 根据 Java 中的 State 名称将 ISO8601 日期时间转换为另一种 ISO8601 格式? - convert ISO8601 date time to another ISO8601 format based on State name in Java? ISO8601日期解析忽略偏移量 - ISO8601 Date Parsing ignoring Offset 如何在 Java 中将 UTC 日期时间转换为 ISO 8601 格式? - how to convert UTC date-time into ISO 8601 format in Java?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM