我对 java 8 日期格式/解析功能有点沮丧。我试图找到 Jackson 配置和 DateTimeFormatter
解析 "2018-02-13T10:20:12.120+0000"
字符串到任何 Java 8 日期,但没有找到它。
这是java.util.Date
工作正常的例子:
Date date = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss.SSSZZZ")
.parse("2018-02-13T10:20:12.120+0000");
相同的格式不适用于新的日期时间 api
ZonedDateTime dateTime = ZonedDateTime.parse("2018-02-13T10:20:12.120+0000",
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'hh:mm:ss.SSSZZZ"));
我们应该能够以适合 FE UI 应用程序的任何格式格式化/解析日期。也许我误解或误会了什么,但我认为
java.util.Date
提供更大的格式灵活性和更易于使用。
最佳答案
tl;博士
直到错误修复:
OffsetDateTime.parse(
"2018-02-13T10:20:12.120+0000" ,
DateTimeFormatter.ofPattern( "uuuu-MM-dd'T'HH:mm:ss.SSSX" )
)
当错误被修复时:
OffsetDateTime.parse( "2018-02-13T10:20:12.120+0000" )
细节
您使用了错误的类。
避免麻烦的旧遗留类,例如
Date
, Calendar
, 和 SimpleDateFormat
.现在被 java.time 取代类。ZonedDateTime
您使用的类很好,它是 java.time 的一部分。但它适用于全时区。您的输入字符串只有一个 offset-from-UTC .相比之下,完整时区是一个区域在过去、现在和 future 的不同时间点有效的偏移量集合。例如,在北美大部分地区的夏令时 (DST) 中,偏移量每年更改两次,当我们将时钟向前移动一个小时时,偏移量在 Spring 变小,而当我们将时钟向后移动一个小时时,偏移量会在秋季恢复到更长的值。小时。OffsetDateTime
对于仅偏移量而不是时区,使用
OffsetDateTime
类(class)。您的输入字符串符合 ISO 8601标准。 java.time 类在解析/生成字符串时默认使用标准格式。所以不需要指定格式模式。
OffsetDateTime odt = OffsetDateTime.parse( "2018-02-13T10:20:12.120+0000" );
嗯,那应该有效。不幸的是,有一个 Java 8 中的错误 (至少在 Java 8 Update 121 之前),该类无法解析忽略小时和分钟之间冒号的偏移量。所以 bug 咬在
+0000
但不是 +00:00
.因此,在修复到来之前,您可以选择两种解决方法:(a) hack,操作输入字符串,或 (b) 定义显式格式模式。技巧:操作输入字符串以插入冒号。
String input = "2018-02-13T10:20:12.120+0000".replace( "+0000" , "+00:00" );
OffsetDateTime odt = OffsetDateTime.parse( input );
DateTimeFormatter
更可靠的解决方法是在
DateTimeFormatter
中定义和传递格式模式。目的。String input = "2018-02-13T10:20:12.120+0000" ;
DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuu-MM-dd'T'HH:mm:ss.SSSX" );
OffsetDateTime odt = OffsetDateTime.parse( input , f );
odt.toString(): 2018-02-13T10:20:12.120Z
顺便说一句,这里有一个提示:我发现对于许多协议(protocol)和库,如果您的偏移量总是带有冒号,总是有小时和分钟(即使分钟为零),并且总是使用填充,那么您的生活会更轻松零(
-05:00
而不是 -5
)。DateTimeFormatterBuilder
对于更灵活的格式化程序,通过
DateTimeFormatterBuilder
创建,见 this excellent Answer关于重复的问题。Instant
如果您想使用始终为 UTC 的值(您应该这样做),请提取
Instant
目的。Instant instant = odt.toInstant();
ZonedDateTime
如果您想通过某个地区的镜头 wall-clock time 观看那一刻,应用时区。
ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = odt.atZoneSameInstant( z );
看到这个 code run live at IdeOne.com .
所有这些都在许多问题的许多答案中多次提及。请在发帖前彻底搜索 Stack Overflow。你会发现几十个甚至几百个例子。
关于 java.time
java.time框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy日期时间类,例如
java.util.Date
, Calendar
, & SimpleDateFormat
.Joda-Time项目,现在在 maintenance mode ,建议迁移到 java.time类。
要了解更多信息,请参阅 Oracle Tutorial .并在 Stack Overflow 上搜索许多示例和解释。规范为 JSR 310 .
您可以直接与您的数据库交换 java.time 对象。使用 JDBC driver符合 JDBC 4.2或以后。不需要字符串,不需要
java.sql.*
类。从哪里获得 java.time 类?
ThreeTen-Extra项目使用附加类扩展 java.time。该项目是 future 可能添加到 java.time 的试验场。您可能会在这里找到一些有用的类,例如
Interval
, YearWeek
, YearQuarter
, 和 more .
关于java - 无法将 ISO 8601 格式的字符串解析为 Java 8 日期,在偏移量中缺少冒号,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59893538/