【问题标题】:Java 8 LocalDateTime ZonedDateTime cannot parse date with time zoneJava 8 LocalDateTime ZonedDateTime 无法解析带时区的日期
【发布时间】:2016-09-12 05:06:24
【问题描述】:

我正在尝试使用 Java 8 新日期模式而不是 Joda,但我遇到了以下问题:

两个

ZonedDateTime.parse("02/05/16 11:51.12.083 +04:30", DateTimeFormatter.ofPattern("dd/MM/yy HH:mm.ss.SSS Z"))

和

LocalDateTime.parse("02/05/16 11:51.12.083 +04:30", DateTimeFormatter.ofPattern("dd/MM/yy HH:mm.ss.SSS Z"))

抛出“java.time.format.DateTimeParseException”异常。 而

org.joda.time.DateTime.parse("02/05/16 11:51.12.083 +04:30", DateTimeFormat.forPattern("dd/MM/yy HH:mm.ss.SSS Z"))

工作正常。

异常原因是:

java.time.format.DateTimeParseException:无法在索引 22 处解析文本“02/05/16 11:51.12.083 +04:30”

我做错了吗?

【问题讨论】:

  • 你试过 OffsetDateTime 吗?它不包含足够的信息来了解实际时区;它所携带的只是与 UTC 的偏移量。
  • 虽然从docs 中的示例来看,似乎冒号被接受为区域偏移分隔符,但是当您尝试它时,它会引发异常。如果您只是删除冒号,它应该可以工作。所以你的日期时间字符串应该是02/05/16 11:51.12.083 +0430
  • @Hank DI 试过这个 OffsetDateTime.parse("02/05/16 11:51.12.083 +04:30",DateTimeFormatter.ofPattern("dd/MM/YY HH:mm.ss. SSS Z")) 但我仍然遇到同样的异常。
  • @Rahul 我不控制输入,所以我无法删除冒号,如果这是您的意思,我不喜欢将其解析为字符串。同样,即使删除了冒号,我仍然会遇到同样的异常。 (ZonedDateTime.parse("02/05/16 11:51.12.083 +0430",DateTimeFormatter.ofPattern("dd/MM/YY HH:mm.ss.SSS Z")))
  • 这次的错误肯定不一样,你有大写的'YY'改成小写的'yy'。

标签: datetime timezone java-8 jodatime java-time


【解决方案1】:

您需要使用XXX 作为区域偏移量。这适用于ZonedDateTime 和OffsetDateTime

ZonedDateTime.parse("02/05/16 11:51.12.083 +04:30", DateTimeFormatter.ofPattern("dd/MM/yy HH:mm.ss.SSS XXX"))

它也将解析为LocalDateTime,但区域偏移量将被截断。

【讨论】:

  • 我试过了,还是一样的异常。 (ZonedDateTime.parse("02/05/16 11:51.12.083 +04:30",DateTimeFormatter.ofPattern("dd/MM/YY HH:mm.ss.SSS X")))
【解决方案2】:

我在这篇帖子Unparsable Date with colon-separated timezone找到了答案

为了解析带有分号时区的时间戳,而不是 DateFormatter javadoc 指示的 X 或 Z,您需要使用 XXX。以下所有工作:

LocalDateTime.parse("02/05/16 11:51.12.083 +04:30", DateTimeFormatter.ofPattern("dd/MM/yy HH:mm.ss.SSS XXX"))

OffsetDateTime.parse("02/05/16 11:51.12.083 +04:30", DateTimeFormatter.ofPattern("dd/MM/yy HH:mm.ss.SSS XXX"))

ZonedDateTime.parse("02/05/16 11:51.12.083 +04:30", DateTimeFormatter.ofPattern("dd/MM/yy HH:mm.ss.SSS XXX"))

【讨论】:

    【解决方案3】:

    使用DateTimeFormatterBuilder 获得对解析器的精确控制并使用appendOffsetId 有效:

    DateTimeFormatter formatter = new DateTimeFormatterBuilder()
          .appendValue(ChronoField.DAY_OF_MONTH, 2)
          .appendLiteral('/')
          .appendValue(ChronoField.MONTH_OF_YEAR, 2)
          .appendLiteral('/')
          .appendValueReduced(ChronoField.YEAR, 2, 2, 2000)
          .appendLiteral(' ')
          .appendValue(ChronoField.HOUR_OF_DAY)
          .appendLiteral(':')
          .appendValue(ChronoField.MINUTE_OF_HOUR)
          .appendLiteral('.')
          .appendValue(ChronoField.SECOND_OF_MINUTE)
          .appendLiteral('.')
          .appendValue(ChronoField.MILLI_OF_SECOND)
          .appendLiteral(' ')
          .appendOffsetId()
          .toFormatter();
    
    OffsetDateTime.parse("02/05/16 11:51.12.083 +04:30", formatter);
    

    【讨论】:

      【解决方案4】:

      如果您阅读the javadoc of DateTimeFormatter,您会发现一节详细介绍了如何使用Z 偏移量(强调我的):

      偏移 Z:这会根据图案字母的数量来格式化偏移。一个、两个或三个字母输出小时和分钟,不带冒号,例如'+0130'。当偏移量为零时,输出将为“+0000”。四个字母输出本地化偏移的完整形式,相当于四个字母的Offset-O。如果偏移量为零,则输出将是相应的本地化偏移量文本。 五个字母输出小时、分钟,如果非零,则可选秒,带冒号。如果偏移量为零,则输出“Z”。六个或更多字母会引发 IllegalArgumentException。

      所以使用 5 Zs 将按预期工作:

      ZonedDateTime.parse("02/05/16 11:51.12.083 +04:30",
                          DateTimeFormatter.ofPattern("dd/MM/yy HH:mm.ss.SSS ZZZZZ"));
      

      请注意,您可以通过以下方式获得类似的结果:

      • z
      • zz
      • zzz
      • zzzz
      • xxx
      • XXX
      • xxxxx
      • XXXXX

      【讨论】:

        猜你喜欢
        • 2015-12-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-04-17
        • 2019-01-21
        • 2016-06-26
        相关资源
        最近更新 更多