【问题标题】:Parsed date is several minutes in the future解析的日期是未来几分钟
【发布时间】:2018-12-04 08:57:33
【问题描述】:

我最近一直在和一个讨厌的海森虫打交道。它让我想起了famous 500-mile email story。我解析收到的日期几乎是ISO 8601,但解析的Date 对象有时是未来几分钟。但是,当我尝试在单元测试中解析相同的数据时,生成的日期总是正确的。

这是我收到的格式:

2018-06-25T13:50:53.984771

我使用JacksonJSON解析它:

new StdDateFormat().parse(timestamp);

以下是一些已解析日期的示例:

2018-06-25T13:50:59.337828
Mon Jun 25 15:56:36 CEST 2018

2018-06-25T13:50:53.984771
Mon Jun 25 16:07:17 CEST 2018

两个小时的差异很好,这只是时区,但分钟呢?它们似乎是随机偏移的!

【问题讨论】:

标签: java maven date datetime jackson


【解决方案1】:

我正在回答我自己的问题,希望有一天它会拯救某人的皮肤。

这个问题在单元测试中没有体现出来,所以我认为服务器可能有问题。我尝试了所有我认为可能有问题的方法,包括研究偏移 15 分钟的奇怪时区,调查 Java 实际花费时间的地方等等。最后,我别无选择,只能对代码进行几处修改,以一分为二。原来是解析器。

这是导致问题的错误: https://github.com/FasterXML/jackson-databind/issues/1668

只有当朋友注意到时间戳末尾的毫秒数对应于以分钟为单位的偏移量时,我才能够找到它:

Original: 2018-06-25T13:50:53.984771
Milliseconds: 984771 ms = 16 minutes 24.77 seconds
Result: Mon Jun 25 16:07:17 CEST 2018

问题在于,解析器将字符串的最后一部分计算为毫秒,并默默地将它们添加到内部 Calendar 对象,它很乐意接受任意数量的毫秒并将它们添加到自身设计的。

问题未在单元测试中体现的原因是我创建的库使用了更新版本的 Jackson,不再包含该错误。但是,使用该库的应用程序已经包含 Jackson,并且由于 Maven 在解析依赖项时选择了正在构建的库 which is closest to the project 的定义,因此它用在它自己的 pom.xml 中声明的旧版本覆盖了我在库中的新版本 Jackson .所以说到底是自找的依赖地狱。

【讨论】:

  • 我不明白你的评论:.. and since Maven prefers the topologically closest declaration of libraries, it overrode my newer version of Jackson with an older one declared in its pom.xml......
  • @khmarbaise 我试图改写答案以使其更清晰,但由于我不确定它是否更好,我还添加了一个指向手册页的链接,该链接解释了发生的事情。
【解决方案2】:

java.time

您正在使用 Java 最早版本中非常麻烦的旧日期时间类(DateCalendar)。这些类现在是遗留的,多年前被 java.time 类取代。

我不是 Jackson 用户,所以我不知道 Jackson 是否添加了对 java.time 的内置支持。但我想很有可能。

如果没有,您似乎可以为此向 Jackson 添加一个支持模块。请参阅this articlethis Question 和此GitHub site

java.time 类使用纳秒分辨率。这意味着最多九 (9) 个十进制数字的小数秒。输入的 6 位数字绰绰有余。

分区与未分区

您还有另一个问题,性质不同。您正在输入缺少任何时区概念或与 UTC 偏移的日期时间。然后你将它保存到一个不同的类型,一个带有时区的类型。不好。你已经注入了不值得的价值。这就像取一个假定为价格的通用数字,然后任意应用输入中未指明的特定货币。

您应该将2018-06-25T13:50:53.984771 等输入解析为LocalDateTime。这种类型故意缺少任何时区或与 UTC 的偏移量,例如您的输入。这种类型确实代表一个特定的时刻,它不是时间轴上的一个点,因为在你应用区域/偏移的上下文之前它没有真正的意义。 p>

如需更多讨论,请在 Stack Overflow 上搜索 LocalDateTimeZonedDateTimeOffsetDateTimeInstant。特别是对于我的一些答案,请搜索“圣诞老人”。


关于java.time

java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.DateCalendarSimpleDateFormat

Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。

要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310

您可以直接与您的数据库交换 java.time 对象。使用符合JDBC 4.2 或更高版本的JDBC driver。不需要字符串,不需要java.sql.* 类。

从哪里获得 java.time 类?

ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore

【讨论】:

  • 嘿,我看到了你的几个答案,我想知道你是否会出现 ;-) 当我阅读你的一个答案时,我才意识到我正在使用过时的 API。您在其中重复了很多内容,也许如果您创建某种摘要博客文章并链接到该文章会更好,所以答案非常简洁,我发现很难找到一个快速参考涵盖最常见的用例,例如“我只有这个 UTC 时间戳并想要解析它”。
【解决方案3】:

使用jackson-modules-java8 和Basil Bourque 在his answer 中推荐的java.time 类型。我没有使用 jackson-modules-java8 的经验,但它肯定可以正确解析小数部分,最多至少 9 位小数,而且它确实支持现代日期时间类型。

【讨论】:

  • 较新的Jackson解析正确,作者重写了很大一部分代码。
猜你喜欢
  • 2015-10-06
  • 1970-01-01
  • 2020-08-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-14
  • 1970-01-01
相关资源
最近更新 更多