无法将iso 8601格式的字符串(偏移量中缺少冒号)解析为java 8日期

j1dl9f46  于 2021-06-30  发布在  Java
关注(0)|答案(3)|浏览(474)

我对Java8的日期格式/解析功能有点失望。我想找到Jackson的配置 DateTimeFormatter 解析 "2018-02-13T10:20:12.120+0000" 字符串到任何Java8日期,但没有找到它。
这是 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 提供更大的格式灵活性和更易于使用。

bf1o4zei

bf1o4zei1#

简:不是虫子,只是你的模式不对。

请使用类型 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小时制的上午/下午的时间,但根据iso-8601的要求,您显然需要“h”表示24小时制。
b) 零偏移形式
如果您想解析零偏移量,例如“+0000”而不是“z”(如iso论文中所述),则不应使用模式符号“x”,而应使用“zzz”。引用模式语法:
偏移量z:根据图案字母的数量设置偏移量的格式。一个、两个或三个字母输出小时和分钟,不带冒号,例如“+0130”。当偏移量为零时,输出将为“+0000”。
c) 您的输入与iso-8601不兼容,因此java中没有bug
您认为“2018-02-13t10:20:12.120+0000”应为有效iso的假设是错误的,因为您混合了基本格式(在偏移部分)和iso文件中明确禁止的扩展格式(见第4.3.2节(示例部分)和第4.3.3d节)。引用iso-8601:
[…]表达式应完全采用基本格式,在这种情况下,使用所需表达式所需的最小分隔符数,或完全采用扩展格式[…]
b的陈述。波克 java.time 有一个bug是基于对iso兼容性的错误期望。比如说 ISO_OFFSET_DATE_TIME 仅描述对扩展iso格式的支持。另请参阅相关的jdk问题。并不是所有的iso-8601变体都被直接支持,因此以正确的方式构建基于模式的解析器是可以的。

bxpogfeg

bxpogfeg2#

如果偏移量+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);
23c0lvtd

23c0lvtd3#

热释光;博士

在修复错误之前:

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的一部分。但它是为一个完整的时区设计的。您的输入字符串与utc之间只有一个偏移量。相比之下,完整时区是一个区域在过去、现在和将来的不同时间点的有效偏移量的集合。例如,在北美大部分地区,随着夏令时(dst)的到来,偏移量每年变化两次,在 Spring ,当我们将时钟向前移动一小时时,偏移量会变小,而在秋季,当我们将时钟向后移动一小时时,偏移量会恢复到更长的值。

偏移日期时间

对于仅偏移量而不是时区,请使用 OffsetDateTime 班级。
您的输入字符串符合iso 8601标准。在解析/生成字符串时,java.time类默认使用标准格式。所以不需要指定格式化模式。

OffsetDateTime odt = OffsetDateTime.parse( "2018-02-13T10:20:12.120+0000" );

好吧,那应该管用的。不幸的是,java8中存在一个bug(至少在java8 update121中是这样),该类无法解析在小时和分钟之间省略冒号的偏移量。所以虫子咬人了 +0000 但不是 +00:00 . 因此,在得到修复之前,您可以从两种解决方法中选择:(a)黑客,操作输入字符串,或(b)定义显式格式模式。
黑客:操纵输入字符串以插入冒号。

String input = "2018-02-13T10:20:12.120+0000".replace( "+0000" , "+00:00" );
OffsetDateTime odt = OffsetDateTime.parse( input );

日期时间格式

更健壮的解决方法是在 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 ,在重复的问题上看到这个极好的答案。

瞬间

如果您想使用总是以utc为单位的值(您应该这样做),请提取 Instant 对象。

Instant instant = odt.toInstant();

分区日期

如果你想通过某个地区的挂钟时间来观察这一时刻,请使用时区。

ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = odt.atZoneSameInstant( z );

请在ideone.com上查看此代码的实时运行。
所有这些都在许多问题的许多答案中被多次提及。请在投递前彻底搜索堆栈溢出。你可能会发现几十个,甚至几百个例子。

关于java.time

java.time框架内置于Java8及更高版本中。这些类取代了旧的遗留日期时间类,例如 java.util.Date , Calendar , & SimpleDateFormat .
现在处于维护模式的joda time项目建议迁移到java.time类。
要了解更多信息,请参阅oracle教程。和搜索堆栈溢出的许多例子和解释。规格为jsr 310。
您可以直接与数据库交换java.time对象。使用符合jdbc 4.2或更高版本的jdbc驱动程序。不需要线,不需要线 java.sql.* 班级。
从哪里获得java.time类?
java se 8、java se 9、java se 10及更高版本
内置的。
标准javaapi的一部分,带有一个捆绑的实现。
Java9添加了一些次要的特性和修复。
java se 6和java se 7
大部分java.time功能都是通过310个后端口后端口移植到Java6和Java7的。
安卓
android包java.time类的更高版本实现。
对于早期的android(<26),threetenabp项目采用了threeten backport(如上所述)。了解如何使用threetenabp…。
threeten额外的项目用额外的类扩展了java.time。这个项目是java.time将来可能添加的一个试验场。您可以在这里找到一些有用的类,例如 Interval , YearWeek , YearQuarter ,等等。

相关问题