我们目前正在从Joda-Time迁移到java.time。我对fromDateFields()
方法有以下疑问。老joda代码:
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 相同的字段值。
从日期查询每个字段并将其分配给LocalDateTime。 如果您一直使用日期作为本地日期,这非常有用, 忽略区域。
达到相同结果的正确方法是什么?
更新(刚刚找到以下解决方案):
lt= LocalDateTime.from(date.toInstant());
答案 0 :(得分:3)
我查看了Joda-Time来源,fromDateFields
方法使用getXXX
中的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
source code,所有获取者都会调用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:2018-02-01T10:50:16.882Z类型为java.time.Instant
因此,您需要将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的默认设置,它也是一个有道理的选择 - 理想情况下,因为有些人只是使用默认值而不考虑它。