我们尝试使用时区偏移量解析以下ISO 8601 DateTime字符串:
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
)这是有道理的,因为时区偏移中的冒号。
java.time.format.DateTimeParseException:无法在索引23处解析文本'2022-03-17T23:00:00.000 + 0000'
但根据Wikipedia,时区偏移有4种有效格式:
<time>Z
<time>±hh:mm
<time>±hhmm
<time>±hh
其他框架/语言可以解析此字符串而不会出现任何问题,例如Javascript Date()
或Jacksons ISO8601Utils
(他们讨论此问题here)
现在我们可以使用复杂的RegEx编写自己的DateTimeFormatter
,但在我看来,java.time
库应该能够默认解析这个有效的ISO 8601字符串,因为它是有效的。
目前我们使用Jacksons ISO8601DateFormat
,但我们更愿意使用官方date.time
库来使用。你解决这个问题的方法是什么?
答案 0 :(得分:19)
如果您要解析所有有效的偏移格式(Z
,±hh:mm
,±hhmm
和±hh
),可以选择使用java.time.format.DateTimeFormatterBuilder
使用可选模式(不幸的是,似乎没有单一的模式字母可以匹配它们):
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
。
如果需要,您还可以定义单个字符串模式,使用[]
分隔可选部分:
// formatter with all possible offset patterns
DateTimeFormatter formatter = DateTimeFormatter
.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS[xxx][xx][X]");
此格式化程序也适用于所有情况,就像上面的格式化程序一样。查看javadoc以获取有关每种模式的更多详细信息。
备注:强>
.SSS
)。另一方面,ISO_LOCAL_DATE_TIME
更灵活:秒和纳秒是可选的,它也接受小数点后的0到9位数。选择最适合您输入数据的那个。答案 1 :(得分:2)
您不需要编写复杂的正则表达式 - 您可以轻松构建一个可以使用该格式的DateTimeFormatter
:
DateTimeFormatter formatter =
DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSX", Locale.ROOT);
OffsetDateTime odt = OffsetDateTime.parse(input, formatter);
这也将接受“Z”而不是“0000”。它将不接受“+00:00”(使用冒号或类似物。鉴于文档,这是令人惊讶的,但如果您的值始终具有没有冒号的UTC偏移量,那么它应该没问题。
答案 2 :(得分:-1)
我不会称之为解决方案,而是一种解决方法。 SimpleDateFormat的map2_chr(
as.numeric(substr(time_hour, 1, 2)),
substr(time_hour, 3, 4),
~case_when(
((.x == 0) & (.y == "00")) ~ "2330-0000",
(as.numeric(.y) > 30) ~ sprintf("%02d30-%02d00", .x, (.x+1)),
TRUE ~ sprintf("%02d00-%02d30", .x, .x)
)
)
模板支持您展示的时区语法,因此您可以执行以下操作:
Z
您仍在使用JVM附带的官方库。一个不是date.time-library的一部分,但仍然是; - )
答案 3 :(得分:-1)
由于它没有冒号,你可以使用自己的格式字符串:
final String input = "2022-03-17T23:00:00.000+0000";
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
Date parsed = df.parse(input);
System.out.println(parsed);