我在应用程序中编写了一个实用程序,该实用程序采用时区并向我返回一个日期(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中没有任何timeZone信息。而是从1970年开始的一个长值包装。所以,我的问题是,是否必须获取发生在日期字段(类型为java.util.Date)中的事务的当前Date-Time瞬间。 ),此实用程序有用吗?
出于所有实际目的,两行代码是否达到同一目的?
transactionEntry.setTime(MyDateHelper.getTimeForTimeZone("UTC+7:00"));
OR
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。无论交易发生在哪个时区,“日期”都将能够正确捕获时间点,对吗?有人可以确认这种理解是正确的吗?
答案 0 :(得分:4)
第一个建议:
Instant transactionTime = Instant.now();
您是正确的,在ZonedDateTime
或Calendar
中时区中的时间都没有意义,当您需要的是时间戳记,时间片刻时。 java.time.Instant
就是那个没有时区的时间点(因此是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)或由于其他原因而使偏移量发生变化的情况下,它可以确保未来发展。
答案 1 :(得分:4)
Answer by Ole V.V.是正确的。我将添加一些讨论。
地球上每个人同时经历的时间轴只有一个(忽略爱因斯坦等人)。按照惯例,我们使用UTC跟踪时间。
学习将UTC视为一个真实的时间。所有其他偏移量和区域仅是UTC的变化。当以程序员或系统管理员的身份工作时,请忘记自己的时区。在UTC上第二次单击您的办公桌或墙壁跟踪时间。在UTC中进行所有日志记录,跟踪,数据存储和数据交换。
用于跟踪UTC时刻的基本类是hashKey
。根据定义,此类的对象始终位于UTC中。此类代替rangeKey
,该类在UTC中也代表了片刻,但存在许多设计缺陷,因此不应使用。 java.time.Instant
的分辨率为纳秒级,比java.util.Date
的毫秒级更好。
为获得更大的灵活性,请使用Instant
类。
Date
然后再次返回。
OffsetDateTime
与UTC的偏移量仅为数小时-数分钟-秒。时区更多。时区是特定区域的人们过去,现在和将来对偏移量的更改的历史记录。
要使用时区,请应用OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;
以获得Instant instant = odt.toInstant() ;
。此类取代了可怕的ZoneId
和ZonedDateTime
类。
Calendar
再次返回。
GregorianCalendar
此ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = instant.atZoneId( z ) ;
,Instant instant = zdt.toInstant() ;
和zdt
代表同一时刻,即时间轴上的同一点。
最后,停止使用odt
和instant
。 Sun,Oracle和JCP社区在采用JSR 310时都放弃了这些类,您也应该这样做。这些遗留类确实是一个可怕的烂摊子。
答案 2 :(得分:3)
但是我只能将时间存储为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());
此page将帮助您了解Instant/Date
,LocalDateTime
,ZonedDateTime
。
我认为您可能会重新考虑设计。为什么只允许java.util.Date
?
根据描述,您似乎确实在乎交易发生的时区。尽管java.util.Date
不支持。这意味着您可以将准确的值(自纪元以来的毫秒数)存储到java.util.Date
,但是由于时区丢失,因此无法用准确的日期时间来表示该值。
您可能需要使用java.time.ZonedDateTime
来实现。