【问题标题】:Joda-Time to java.time migration 'fromDateFields()'Joda-Time 到 java.time 迁移 'fromDateFields()'
【发布时间】:2018-07-10 21:48:40
【问题描述】:

我们目前正在从 Joda-Time 迁移到 java.time。我对fromDateFields()方法有以下疑问。旧约达代码:

Date date = new Date(); //some java Date
LocalDateTime lt = LocalDateTime.fromDateFields(date);

一位同事将其迁移到以下几行(java.time 代码):

lt = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();

正确吗? Joda-Time docs描述方法fromeDateFields是这样的:

从 java.util.Date 构造一个 LocalDateTime,完全使用 相同的字段值。

每个字段都从 Date 中查询并分配给 LocalDateTime。 如果您一直使用 Date 作为本地日期,这很有用, 忽略区域

达到相同结果的正确方法是什么?

更新(刚刚找到以下解决方案):

lt= LocalDateTime.from(date.toInstant());

【问题讨论】:

  • 我会说您同事的代码是正确的,但是如果您想确保获得完全相同的结果,请实施相同的方法。见 Joda-Time 来源:github.com/JodaOrg/joda-time/blob/master/src/main/java/org/joda/….
  • 看起来正确。请记住,joda 文档还说:“传输本地字段值,使用 JDK 时区数据计算”
  • 没想到看Joda-time源代码。好提示!还刚刚找到以下看起来更好的解决方案? LocalDateTime.from(date.toInstant()); 个人不喜欢上面代码中的zone部分...

标签: java jodatime java-time localdate java.time.instant


【解决方案1】:

我查看了 Joda-Time 源,fromDateFields 方法使用来自java.util.DategetXXX 方法来获取日期/时间字段的值。类似的东西(我使用的是 Joda-Time 2.9.9):

return new LocalDateTime(
    date.getYear() + 1900,
    date.getMonth() + 1,
    date.getDate(),
    date.getHours(),
    date.getMinutes(),
    date.getSeconds(),
    (((int) (date.getTime() % 1000)) + 1000) % 1000
);

如果您查看javadoc,您会看到所有这些方法都返回对应的值以当地时区解释。这意味着使用 JVM 默认时区是隐式

其实看Date source code,所有的getter都调用normalize(),这是一种使用默认时区转换字段的方法。

你说我个人不喜欢时区部分,但在 Joda-Time 中,它隐含/间接地使用默认时区。

使用区域是有意义的,因为java.util.Date represents a point in the timeline (a specific instant),没有任何时区信息。同一时刻可以对应世界不同地区的不同日期和时间,因此您需要一个时区来进行这种转换。

Joda-Time 使用 Date::getXXX 方法,隐式使用默认时区。但在java.time 中,事情必须更明确,所以必须使用ZoneId 对象。

顺便说一句,您的解决方案 (LocalDateTime.from(date.toInstant())) 对我不起作用。在 Java 8 中,它给出了一个错误:

java.time.DateTimeException:无法从 TemporalAccessor 获取 LocalDateTime:java.time.Instant 类型的 2018-02-01T10:50:16.882Z

所以你需要将Date 转换为Instant,然后告诉你想要的时区,然后获取本地部分,就像你已经在做的那样:

LocalDateTime dt = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();

或者:

// the result is the same
LocalDateTime dt = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());

虽然java.time 强制你使用时区,但我相信这是一件好事,因为它让你思考它,而不是在幕后做一些“魔术”。

如果需要,您甚至可以将其更改为其他时区(例如ZoneId.of("America/New_York"))。即使您最终使用了 JVM 的默认值,这也是一个明智的选择 - 理想情况下,因为有些人只是使用默认值而不考虑它。

【讨论】:

    猜你喜欢
    • 2014-04-04
    • 2020-07-08
    • 1970-01-01
    • 2015-06-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多