为了账号安全,请及时绑定邮箱和手机立即绑定

Calendar.getInstance with TimeZone vs new Date()

Calendar.getInstance with TimeZone vs new Date()

一只名叫tom的猫 2021-11-03 14:52:16
我在我的应用程序中编写了一个实用程序,它接受一个时区并返回一个日期(java.util.Date),如下所示 -// Inside MyDateHelper.javapublic static java.util.Date getTimeForTimeZone(String timeZoneId){    final Date currentDate = Calendar.getInstance(TimeZone.getTimeZone(timeZoneId)).getTime();    return currentDate;}我在互联网上进行了研究,发现 Date 中没有任何时区信息。相反,它是一个从 1970 年开始的 long 值的包装器。所以,我的问题是,我是否必须获取当前发生的事务的当前日期时间瞬间,以存储在日期字段(java.util.Date 类型)中),这个实用程序有什么用吗?就所有实际目的而言,这两行代码是否实现了相同的目标?transactionEntry.setTime(MyDateHelper.getTimeForTimeZone("UTC+7:00"));或者transactionEntry.setTime(new Date());我还检查了新的 Java 8 Time API,但就我的目的而言,我认为这样做也是一种矫枉过正,仅此而已new Date()-Date date4 = new Date();LocalDateTime localDate = date4.toInstant().atZone(ZoneId.of("UTC+07:00")).toLocalDateTime();final ZonedDateTime dateWithZone = localDate.atZone(ZoneId.of("UTC+07:00"));Date dateOutput = Date.from(dateWithZone.toInstant());transactionEntry.setTime(dateOutput);整个目的是用时区捕获事务发生的时间,但我只能将时间存储为 java.util.Date。无论交易发生在哪个时区,Date 都能够正确捕捉时间,对吗?有人可以确认这种理解是正确的吗?
查看完整描述

3 回答

?
慕工程0101907

TA贡献1887条经验 获得超5个赞

Ole VV回答是正确的。我将添加一些讨论。

地球上的每个人同时经历的时间线只有一个(忽略爱因斯坦等人)。按照惯例,我们以 UTC 跟踪该时间。

学会将 UTC 视为唯一的真实时间。所有其他偏移量和区域只是 UTC 的一种变体。在作为程序员或系统管理员工作时,忘记你自己狭隘的时区。在您的桌面或墙上保持第二次点击以 UTC 跟踪时间。在 UTC 中完成所有日志记录、跟踪、数据存储和数据交换。

在 UTC 中跟踪时刻的基本类是java.time.Instant. 根据定义,此类的对象始终采用 UTC。这个类取代了java.util.Date,它也代表 UTC 中的一个时刻,但有很多设计缺陷,永远不应该使用。Instant具有纳秒级的分辨率,比 的毫秒级更精细Date

为了获得更大的灵活性,请使用OffsetDateTime类。

OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;

然后再回来。

Instant instant = odt.toInstant() ;

UTC 的偏移量只是一些小时-分钟-秒。时区要多得多。时区是特定地区人民使用的偏移量的过去、现在和未来变化的历史。

要使用时区,请应用 aZoneId以获取ZonedDateTime. 该类取代了可怕CalendarGregorianCalendar类。

ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = instant.atZoneId( z ) ;

又要回去了。

Instant instant = zdt.toInstant() ;

zdtodt, 和instant都代表了同一时刻,时间线上的同一点。

最后,停止使用DateandCalendar。Sun、Oracle 和 JCP 社区在采用 JSR 310 时都放弃了这些类,您也应该如此。那些遗留课程真的是一团糟。


查看完整回答
反对 回复 2021-11-03
?
郎朗坤

TA贡献1921条经验 获得超9个赞

第一个建议:


    Instant transactionTime = Instant.now();

您是正确的,在您的时区中浏览时间是没有意义的,无论是在 aZonedDateTime还是 a 中Calendar,当您需要的是时间戳,时间片刻。java.time.Instant就是这样,一个没有时区的时间点(因此是 a 的最直接替代品Date)。您可能应该尽可能使用 java.time,现代 Java 日期和时间 API。Date,Calendar并且TimeZone不仅已经过时,而且还存在一系列设计问题。现代课程更适合使用。


如果您的事务入口类在内部使用java.util.Date并且您现在不想升级其内部逻辑,您仍然可以添加一个setTime接受Instant.


public void setTime(Instant time) {

    // Delegate to the old method that accepts a java.util.Date

    setTime(Date.from(time));

}

下一步可能是标记接受Date已弃用的方法。


第二个建议,如果你坚持Date我仍然喜欢:


    Date transactionTime = Date.from(Instant.now());

它的作用与 相同new Date(),但更直接地告诉读者您获得了当前时刻。我看不出这怎么可能不是优势。


顺便说一句,如果您确实想使用时区,则应该使用正确的时区 ID,Antarctica/Davis而不是偏移量。同样,它会告诉您的读者更多有关您的意图的信息,并且在某些时候引入夏令时 (DST) 或偏移量因其他原因发生变化时是面向未来的。


查看完整回答
反对 回复 2021-11-03
?
慕勒3428872

TA贡献1848条经验 获得超6个赞

但我只能将时间存储为 java.util.Date。


那么时区无所谓,


Calendar calendar = Calendar.getInstance();


calendar.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles"));

Date america = calendar.getTime();


calendar.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));

Date shanghai = calendar.getTime();


System.out.println(america.equals(shanghai)); // true

你可以只使用:


transactionEntry.setTime(new Date());

此页面将帮助您了解Instant/Date, LocalDateTime, ZonedDateTime。


我想你可能会重新考虑设计。为什么只java.util.Date允许?


从描述来看,您似乎确实关心事务发生的时区。虽然java.util.Date只是不支持它。这意味着您可以将准确的值(自纪元以来的毫秒数)存储到java.util.Date,但该值不能用准确的日期时间表示,因为时区已丢失。


您可能需要使用 java.time.ZonedDateTime来实现它。


查看完整回答
反对 回复 2021-11-03
  • 3 回答
  • 0 关注
  • 187 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信