java - 无法将 ISO 8601 格式的字符串解析为 Java 8 日期,在偏移量中缺少冒号

标签 java parsing datetime java-8 iso8601

我对 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 类?
  • Java SE 8 , Java SE 9 , Java SE 10 , 然后
  • 内置。
  • 具有捆绑实现的标准 Java API 的一部分。
  • Java 9 添加了一些小功能和修复。
  • Java SE 6Java SE 7
  • ThreeTen-Backport 中,大部分 java.time 功能被反向移植到 Java 6 和 7。 .
  • Android
  • java.time 类的更高版本的 Android 捆绑实现。
  • 对于早期的 Android (<26),ThreeTenABP项目适应 ThreeTen-Backport (上文提到的)。见 How to use ThreeTenABP… .

  • ThreeTen-Extra项目使用附加类扩展 java.time。该项目是 future 可能添加到 java.time 的试验场。您可能会在这里找到一些有用的类,例如 Interval , YearWeek , YearQuarter , 和 more .

    关于java - 无法将 ISO 8601 格式的字符串解析为 Java 8 日期,在偏移量中缺少冒号,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59893538/

    相关文章:

    java - 目标 org.springframework.boot 的执行默认值 :spring-boot-maven-plugin:1. 0.2.RELEASE:repackage failed: Source must refer to an existing file

    java - 将日期从字符串表示形式转换为数字表示形式,然后再转换回来

    PHP 简单 HTML DOM 或 Python-BSoup : which one is the easier approach?

    vba - Excel VBA 导入 .txt 文件导致日期格式错误

    python - 给定日期时间列的 Pandas groupby week

    java - 无法为 IE8 浏览器添加 Cookie(Java、Selenium Grid、WebDriver 2.41.0)

    java - 为什么Spring JdbcTemplate是线程安全的?

    java - java中的正则表达式: find all _overlapping_ variants (ab)|(bc)|(de)|(f) in abcdef

    php - 如何防止我的网站表单被解析?

    java - 我可以使用什么库来解析 Java 中的单词?