Java 8 日期和时间:解析偏移量中没有冒号的 ISO 8601 字符串 [英] Java 8 Date and Time: parse ISO 8601 string without colon in offset

查看:34
本文介绍了Java 8 日期和时间:解析偏移量中没有冒号的 ISO 8601 字符串的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们尝试解析以下带有时区偏移量的 ISO 8601 日期时间字符串:

We try to parse the following ISO 8601 DateTime String with timezone offset:

final String input = "2022-03-17T23:00:00.000+0000";

OffsetDateTime.parse(input);
LocalDateTime.parse(input, DateTimeFormatter.ISO_OFFSET_DATE_TIME);

由于时区偏移中的冒号,这两种方法都失败了(这是有道理的,因为 OffsetDateTime 也使用了 DateTimeFormatter.ISO_OFFSET_DATE_TIME).

Both approaches fail (which makes sense as OffsetDateTime also use the DateTimeFormatter.ISO_OFFSET_DATE_TIME) because of the colon in the timezone offset.

java.time.format.DateTimeParseException: 无法在索引 23 处解析文本2022-03-17T23:00:00.000+0000"

java.time.format.DateTimeParseException: Text '2022-03-17T23:00:00.000+0000' could not be parsed at index 23

但根据 维基百科,时区偏移有 4 种有效格式:

But according to Wikipedia there are 4 valid formats for a timezone offset:

<time>Z 
<time>±hh:mm 
<time>±hhmm 
<time>±hh

其他框架/语言可以毫无问题地解析这个字符串,例如Javascript Date() 或 Jacksons ISO8601Utils(他们讨论了这个问题 这里)

Other frameworks/languages can parse this string without any issues, e.g. the Javascript Date() or Jacksons ISO8601Utils (they discuss this issue here)

现在我们可以使用复杂的 RegEx 编写我们自己的 DateTimeFormatter,但在我看来,java.time 库默认应该能够解析这个有效的 ISO 8601 字符串因为它是有效的.

Now we could write our own DateTimeFormatter with a complex RegEx, but in my opinion the java.time library should be able to parse this valid ISO 8601 string by default as it is a valid one.

现在我们使用 Jacksons ISO8601DateFormat,但我们更愿意使用官方的 date.time 库来使用.您将采用什么方法来解决这个问题?

For now we use Jacksons ISO8601DateFormat, but we would prefer to use the official date.time library to work with. What would be your approach to tackle this issue?

推荐答案

如果要解析所有有效格式的偏移量 (Z, ±hh:mm, ±hhmm±hh),一种替代方法是使用带有可选模式的 java.time.format.DateTimeFormatterBuilder(不幸的是,似乎有没有一个模式字母可以匹配它们):

If you want to parse all valid formats of offsets (Z, ±hh:mm, ±hhmm and ±hh), one alternative is to use a java.time.format.DateTimeFormatterBuilder with optional patterns (unfortunatelly, it seems that there's no single pattern letter to match them all):

DateTimeFormatter formatter = new DateTimeFormatterBuilder()
    // date/time
    .append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
    // offset (hh:mm - "+00:00" when it's zero)
    .optionalStart().appendOffset("+HH:MM", "+00:00").optionalEnd()
    // offset (hhmm - "+0000" when it's zero)
    .optionalStart().appendOffset("+HHMM", "+0000").optionalEnd()
    // offset (hh - "Z" when it's zero)
    .optionalStart().appendOffset("+HH", "Z").optionalEnd()
    // create formatter
    .toFormatter();
System.out.println(OffsetDateTime.parse("2022-03-17T23:00:00.000+0000", formatter));
System.out.println(OffsetDateTime.parse("2022-03-17T23:00:00.000+00", formatter));
System.out.println(OffsetDateTime.parse("2022-03-17T23:00:00.000+00:00", formatter));
System.out.println(OffsetDateTime.parse("2022-03-17T23:00:00.000Z", formatter));

以上四种情况都会解析为2022-03-17T23:00Z.

All the four cases above will parse it to 2022-03-17T23:00Z.

如果需要,您还可以定义单个字符串模式,使用 [] 分隔可选部分:

You can also define a single string pattern if you want, using [] to delimiter the optional sections:

// formatter with all possible offset patterns
DateTimeFormatter formatter = DateTimeFormatter
    .ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS[xxx][xx][X]");

这个格式化程序也适用于所有情况,就像前面的格式化程序一样.检查 javadoc 以获取有关每个模式的更多详细信息.

This formatter also works for all cases, just like the previous formatter above. Check the javadoc to get more details about each pattern.

注意事项:

  • 具有上述可选部分的格式化程序有利于解析,但不适用于格式化.格式化时,它会打印所有可选部分,这意味着它会多次打印偏移量.因此,要格式化日期,只需使用其他格式化程序即可.
  • 第二个格式化程序只接受小数点后的 3 位数字(因为 .SSS).另一方面,ISO_LOCAL_DATE_TIME 更灵活:秒和纳秒是可选的,它也接受小数点后 0 到 9 位数字.选择最适合您的输入数据的一种.
  • A formatter with optional sections like the above is good for parsing, but not for formatting. When formatting, it'll print all the optional sections, which means it'll print the offset many times. So, to format the date, just use another formatter.
  • The second formatter accepts exactly 3 digits after the decimal point (because of .SSS). On the other hand, ISO_LOCAL_DATE_TIME is more flexible: the seconds and nanoseconds are optional, and it also accepts from 0 to 9 digits after the decimal point. Choose the one that works best for your input data.

这篇关于Java 8 日期和时间:解析偏移量中没有冒号的 ISO 8601 字符串的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆