我对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
提供了更多格式灵活性并且更易于使用。
答案 0 :(得分:20)
直到错误修复:
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。相比之下,全时区是对不同时间点,过去,现在和将来的区域有效的偏移的集合。例如,在北美大部分地区使用夏令时(DST)时,每年两次的偏差会在春季变小,因为我们将时钟向前移动一小时,而在秋季我们将时钟向后移动时恢复到更长的值小时。
OffsetDateTime
仅对于偏移而不是时区,请使用OffsetDateTime
类。
您的输入字符串符合ISO 8601标准。在解析/生成字符串时,java.time类默认使用标准格式。因此无需指定格式化模式。
OffsetDateTime odt = OffsetDateTime.parse( "2018-02-13T10:20:12.120+0000" );
嗯,应该有效。遗憾的是,Java 8中存在错误(至少通过Java 8 Update 121),该类无法解析在小时和分钟之间省略冒号的偏移量。因此,错误会导致+0000
但不会+00:00
。因此,在修复程序到达之前,您可以选择两种解决方法:(a)hack,操作输入字符串,或(b)定义显式格式化模式。
hack:操纵输入字符串以插入冒号。
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
顺便说一句,这里有一个提示:我发现,对于许多协议和库,如果你的偏移总是有冒号,你的生活会更容易,总是有小时和分钟(即使分钟为零),并且总是如此使用填充零(-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 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。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如Interval
,YearWeek
,YearQuarter
和more。
答案 1 :(得分:2)
请使用专为时区偏移量设计的OffsetDateTime
类型,并以这种方式使用模式:
OffsetDateTime odt =
OffsetDateTime.parse(
"2018-02-13T10:20:12.120+0000" ,
DateTimeFormatter.ofPattern( "uuuu-MM-dd'T'HH:mm:ss.SSSZZZ" )
)
a)12小时制与24小时制
“ h”表示12小时制的AM / PM的小时数,但显然,按照ISO-8601的要求,在24小时制中需要“ H”。
b)零偏移的形式
如果要解析零偏移量,例如“ +0000”而不是“ Z”(如ISO纸张中所述),则不应使用模式符号“ X”,而应使用“ ZZZ”。引用pattern syntax:
Offset Z(偏移Z):这将根据图案数量格式化偏移 字母。一,二或三个字母输出小时和分钟, 没有冒号,例如'+0130'。当 偏移量为零。
c)您的输入不兼容ISO-8601,因此Java中没有错误
您认为“ 2018-02-13T10:20:12.120 + 0000”应为有效ISO的假设是错误的,因为您混合了基本格式(在胶印部分中)和扩展格式,而ISO纸中明确禁止使用扩展格式(请参见第4.3.2节(示例部分)和4.3.3d)。引用ISO-8601:
[...]表达式应完全采用基本格式,其中 情况下所需的最小分隔符数 使用表达式,或完全使用扩展格式[...]
B。Bourque关于java.time
有错误的说法是基于对ISO兼容性的同样错误预期。假设ISO_OFFSET_DATE_TIME
的文档仅描述了对扩展ISO格式的支持。另请参阅相关的JDK issue。并非所有ISO-8601变体都直接受支持,因此以正确的方式基于模式的解析器构造是可以的。
答案 2 :(得分:0)
如果偏移量+0000,请尝试
DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuu-MM-dd'T'HH:mm:ss.SSSX" )
LocalDate from =LocalDate.parse("2018-02-13T10:20:12.120+0000",f);