如何把ZonedDateTime转换成Joda DateTime

how to convert from ZonedDateTime to Joda DateTime

提问人:Tim Pigden 提问时间:1/26/2015 最后编辑:leppieTim Pigden 更新时间:12/6/2018 访问量:18106

问:

我已经切换到 threeten 作为日期时间,但我仍然有一个第三方工具,它使用 joda 将带有时区的时间戳写入数据库,我需要从一个转换为另一个。 最好的方法是什么? 作为一种解决方法,我尝试了DateTime.parse(zdt.toString),但它失败了,因为joda不喜欢区域格式

格式无效:“2015-01-25T23:35:07.684Z[Europe/London]”在“[Europe/London]”处格式不正确

Java Jodatime ThreeTenBP

评论


答:

9赞 Meno Hochschild 1/26/2015 #1
ZonedDateTime zdt = 
  ZonedDateTime.of(
    2015, 1, 25, 23, 35, 7, 684000000, 
    ZoneId.of("Europe/London"));

System.out.println(zdt); // 2015-01-25T23:35:07.684Z[Europe/London]
System.out.println(zdt.getZone().getId()); // Europe/London
System.out.println(zdt.toInstant().toEpochMilli()); // 1422228907684

DateTimeZone london = DateTimeZone.forID(zdt.getZone().getId());
DateTime dt = new DateTime(zdt.toInstant().toEpochMilli(), london);
System.out.println(dt); // 2015-01-25T23:35:07.684Z

如果区域 ID 转换可能因任何不受支持或无法识别的 ID 而崩溃,我建议

  • 捕获并记录它,
  • 对 tz-repositories 进行更新(对于 Joda:更新到最新版本,对于 JDK:使用 tz-updater-tool)

这通常是比默默地回退到任何任意的 tz 偏移量(如 UTC)更好的策略。

评论

0赞 Meno Hochschild 12/6/2018
对于反对者,在你打算按照 James Ding 的回答中的建议使用之前,请三思而后行。对于不受支持的 ID,切换回 UTC 可能比崩溃更糟糕。TimeZone.getTimeZone(...)
22赞 James Ding 5/20/2016 #2

请注意,使用 DateTimeZone.forID(...) 是不安全的,这可能会引发 DateTimeParseException,因为通常 ZoneOffset.UTC 的 ID “Z” 无法被 DateTimeZone 识别。

为了将 ZonedDateTime 转换为 DateTime,我建议的是:

return new DateTime(
    zonedDateTime.toInstant().toEpochMilli(),
    DateTimeZone.forTimeZone(TimeZone.getTimeZone(zonedDateTime.getZone())));

评论

0赞 ChrisDekker 12/5/2018
这应该是公认的答案。我们遇到了这个确切的问题!
0赞 Meno Hochschild 12/6/2018
@ChrisDekker 在每种情况下,区域标识符都没有完美的转换。虽然该表达式可能比 Joda-Time 更适合 Z-literals(表示 UTC),但这样的表达式对于其他 ID 可能会默默失败,但不是例外,而是任意回退到 UTC(这更糟),请参阅 API-doc:“返回:指定的时区,如果无法理解给定的 ID,则返回 GMT 区域”,我的回答只是解决了 OP 在问题中提出的特殊示例, 但我不会假装它适用于每个区域 ID。TimeZone.getTimeZone(zoneId)
0赞 Meno Hochschild 12/6/2018
这个建议答案的主要问题是它假装适用于所有标识符,尽管无法识别的 ID 可以通过表达式切换到 UTC - 没有任何例外。Joda-Time 和 JDK 的底层时区存储库知道不同的有效 ID 集,这一事实无法通过任何“天才”或“智能”转换代码来治愈。TimeZone.getTimeZone(zoneId)
2赞 pabl0rg 11/18/2016 #3

这里有一个 Kotlin 扩展来做同样的事情(以防你以这种方式编码)

fun ZonedDateTime.toDateTime(): DateTime =
    DateTime(this.toInstant().toEpochMilli(), 
        DateTimeZone.forTimeZone(TimeZone.getTimeZone(this.zone)))