Calendar.getInstance with TimeZone vs new Date()

我在我的应用程序中编写了一个实用程序,它接受一个时区并返回一个日期(java.util.Date),如下所示 -


// Inside MyDateHelper.java

public 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 都能够正确捕捉时间,对吗?有人可以确认这种理解是正确的吗?


一只名叫tom的猫
浏览 188回答 3
3回答

慕工程0101907

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. 该类取代了可怕Calendar和GregorianCalendar类。ZoneId z = ZoneId.of( "Africa/Tunis" ) ; ZonedDateTime zdt = instant.atZoneId( z ) ;又要回去了。Instant instant = zdt.toInstant() ;这zdt, odt, 和instant都代表了同一时刻,时间线上的同一点。最后,停止使用DateandCalendar。Sun、Oracle 和 JCP 社区在采用 JSR 310 时都放弃了这些类,您也应该如此。那些遗留课程真的是一团糟。

郎朗坤

第一个建议:    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) 或偏移量因其他原因发生变化时是面向未来的。

慕勒3428872

但我只能将时间存储为 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来实现它。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java