Java 8中的LocalDateTime和ZonedDateTime无法解析带时区的日期

7
我正在尝试使用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”

我做错了什么吗?


3
你尝试过使用OffsetDateTime吗?它没有足够的信息来确定一个实际的时区,它只包含与UTC的偏移量。 - Hank D
尽管从文档的示例中看来,冒号被接受为区域偏移分隔符,但当您尝试时,它会抛出异常。如果您只是删除冒号,它应该可以工作。因此,您的日期时间字符串应为02/05/16 11:51.12.083 +0430 - Rahul Sharma
@Rahul 我无法控制输入,因此无法删除冒号。如果您的意思是将其解析为字符串,我不喜欢这样做。即使删除了冒号,我仍然会收到相同的异常。(ZonedDateTime.parse("02/05/16 11:51.12.083 +0430",DateTimeFormatter.ofPattern("dd/MM/YY HH:mm.ss.SSS Z"))) - ampofila
这次的错误一定不同,你把大写字母'YY'改成小写字母'yy'。 - Rahul Sharma
OffsetDateTime 是最适合此问题中所见数据的类型。 LocalDateTime 有意丢弃了UTC偏移量信息。 ZonedDateTime 用于完整的时区,这包括一个偏移值和处理夏令时等异常情况的规则。 - Basil Bourque
显示剩余3条评论
4个回答

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

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

因此,使用5个Z将按预期工作:
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

2

我在这篇文章中找到了答案:Unparsable Date with colon-separated timezone

如果要解析带有分号而不是X或Z作为DateFormatter javadoc所示时区的时间戳,您需要使用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"))

1
使用 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);

0

你需要使用XXX来表示时区偏移量。这适用于ZonedDateTimeOffsetDateTime

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"))) - ampofila

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接