3

我们目前正在从 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 文档描述了这样的方法fromeDateFields

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

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

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

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

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

1 回答 1

3

我查看了 Joda-Time 源,该fromDateFields方法使用getXXXfrom 的方法java.util.Date来获取日期/时间字段的值。类似的东西(我使用的是 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源代码,所有的 getter 调用normalize(),这是一个使用默认时区转换字段的方法。

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

使用区域是有意义的,因为 ajava.util.Date代表时间线中的一个点(特定时刻),没有任何时区信息。同一时刻可以对应世界不同地区的不同日期和时间,因此您需要一个时区来进行此转换。

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

因此,您需要将 to 转换DateInstant,然后告诉您想要的时区,然后获取本地部分,就像您已经在做的那样:

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 的默认值,这也是一个明智的选择 - 理想情况下,因为有些人只是使用默认值而不考虑它。

于 2018-02-01T11:06:51.400 回答