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

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

问题描述

我们尝试使用时区偏移量解析以下ISO 8601 DateTime字符串:

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:无法在索引处解析文本'2022-03-17T23:00:00.000 + 0000' 23

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)

现在我们可以编写自己的 DateTimeFormatter 带有复杂的RegEx,但在我看来, 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 ,但我们更愿意使用官方的日期.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.

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

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("uuuu-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天全站免登陆