java.util.Date和Zoneddatetime有什么区别?

ej83mcc0  于 2023-05-05  发布在  Java
关注(0)|答案(3)|浏览(279)

当使用util.date并从浏览器提供日期和时间到服务,然后保存到数据库并将其取回时,它会提供不同的日期时间,而不是直接从服务设置zoneddatetime
任何帮助将不胜感激。

ijnw1ujt

ijnw1ujt1#

tl;dr

java.util.Date和Zoneddatetime有什么区别?

  • Date表示UTC中的时刻,而ZonedDateTime表示特定时区中的时刻。
  • Date是一个糟糕的类,充满了设计缺陷,永远不应该使用,而ZonedDateTime是一个来自 java.time 包的现代类,您会发现它非常有用。

Java提供了两个非常不同的框架来处理日期时间工作:一组非常笨拙和失败的遗留类,以及一组在java.time包中找到的现代行业领先的类。
传统与现代:

  • java.util.Date已替换为java.time.Instant
  • 两者都代表UTC中的一个时刻。
  • java.util.GregorianCalendar已替换为java.time.ZonedDateTime
  • 两者都代表在特定时区看到的时刻。

java.util.Date

Date类表示UTC中的一个时刻。也就是说,一个日期,一天中的时间,加上UTC的上下文。
在内部,它是自1970年第一时刻的历元参考日期(UTC,1970-01- 01 T00:00:00 Z)以来的毫秒计数。
更复杂的是:

  • 创建时有一个时区捕获,存储在内部深处,没有getter或setter。所以在大多数情况下,我们可以忽略这个区域,尽管它确实适用于这个类的equals实现。
  • 当调用toString时,这个类有一个非常令人困惑的行为,即动态应用JVM的当前时区,同时生成文本来表示这个对象的值。虽然初衷是好的,但是这个反特性给试图学习日期时间处理的Java程序员带来了难以估量的痛苦。

是的,这个类很混乱,一堆糟糕的设计决策。由后来添加的java.util.CalendarGregorianCalendar复合。
所有这些与最早版本的Java捆绑在一起的麻烦的日期-时间类现在完全被 java.time 类所取代。
特别地,java.util.Datejava.time.Instant替换。两者都表示从1970 UTC历元开始计数的UTC时刻。但Instant的分辨率更高,为nanoseconds,而不是milliseconds
您可以通过调用添加到旧类的新方法,在遗留类Date和现代类Instant之间来回转换。通常,您会避免使用Date。但是当与尚未更新到 java.time 的旧代码交互时,您可能需要进行转换。

java.time.ZonedDateTime

现代类ZonedDateTime表示某个地区(时区)的人们使用的挂钟时间中的某个时刻。
所以InstantZonedDateTime是相似的,它们都代表一个时刻,时间轴上的一个特定点。不同之处在于ZonedDateTime知道时区的规则。因此,ZonedDateTime知道如何解释诸如夏令时(DST)或政治家要求的其他计时更改等异常情况。
你可以把它想成:
ZonedDateTime =(Instant + ZoneId
我们可以通过将时区(ZoneId)应用到Instant对象来轻松地从UTC调整到某个时区。

Instant instant = Instant.now() ;             // Capture the current moment as seen in UTC.
ZoneId z = ZoneId.of( "Asia/Tokyo" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;     // Apply a time zone to see the same moment through the wall-clock time in use by the people of a particular region (a time zone).

看看这个code run live at IdeOne.com。请注意不同的日期和不同的时间,但同一时刻。
instant.toString():2019-02-27T19:32:43.366Z
public void run():2019-02- 28 T04:32:43.366+09:00[亚洲/东京]
关键概念:InstantZonedDateTime都代表同一时刻,时间轴上同一个同时发生的点。他们在墙上的时钟时间不同。例如,如果一个在日本的人打电话给一个在冰岛的人(冰岛的时钟一直使用UTC),他们都抬头看挂在各自墙上的时钟,他们会看到一天中不同的时间,甚至可能是月历上不同的日期。同样的时刻,不同的挂钟时间。
至于遗留类,ZonedDateTime的等价物是GregorianCalendar,它是java.util.Calendar的具体实现。实际上,旧类GregorianCalendar获得了新的方法来转换为ZonedDateTime

ZonedDateTime zdt = myGregorianCalendar.toZonedDateTime();  // Convert from legacy to modern class.

还有...

GregorianCalendar gc = GregorianCalendar.from( zdt ) ;      // Convert from modern to legacy class.

总结

因此,Date相当于Instant,两者都是UTC中的时刻。但ZonedDateTime与两者的不同之处在于,一个时区通过应用一个地区的人们的挂钟时间调整的透镜来调整对时刻的感知。
温馨提示:

***不要使用Date。**当拿到Date时,立即转换为Instant。然后继续你的商业逻辑。
***大多数工作都是在UTC中进行的。**跟踪时刻、调试、日志记录、交换日期-时间值以及持久化到数据库通常都应该在UTC中进行。当你作为一个程序员工作时,要学会忘记你自己的时区。在你的办公桌上放一个时钟,设定为UTC。

数据库

问题提到数据库工作。下面是一个简短的总结。搜索堆栈溢出以获得更多细节,因为这已经被处理过很多次了。
从JDBC4.2开始,我们可以直接与数据库交换 java.time 对象。使用PreparedStatement::setObjectResultSet::getObject。再也不需要接触可怕的java.sql.*类,如java.sql.Timestamp
您可以交换Instant,但JDBC规范并不要求这样做。规范要求使用OffsetDateTime

检索。

OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;

还有储藏室

myPreparedStatement.setObject( … , odt ) ;

如果你有一个Instant,使用常量ZoneOffset.UTC转换为OffsetDateTime

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

要通过某个区域的挂钟时间查看该时刻,请应用ZoneId

ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = odt.atZoneSameInstant( z ) ;

要将ZonedDateTime存储到数据库中,请转换为OffsetDateTime。这将去除时区信息(过去、现在和未来对该地区人民使用的偏移量所做的更改的历史,这些更改由他们的政治家决定),留下日期、时间和UTC偏移量(小时-分钟-秒的数量)。

OffsetDateTime odt = zdt.toOffsetDateTime();

大多数数据库为SQL标准类型TIMESTAMP WITH TIMESTAMP的列存储UTC时间。当将OffsetDateTime提交到数据库时,JDBC驱动程序可能会将OffsetDateTime中的偏移量调整为0小时-分钟-秒(UTC本身)。但我喜欢明确地这样做。它使调试更容易,并向读者展示了我对存储在UTC中的时刻的理解。

OffsetDateTime odt = zdt.toOffsetDateTime().withOffsetSameInstant( ZoneOffset.UTC ) ;

yduiuuwa

yduiuuwa2#

java.util.Date是一个几乎被弃用的类,它提供了一个围绕毫秒值的 Package 器。它不提供任何有关时区的信息,没有任何有用的方法,你应该永远避免使用它。
ZonedDateTime是新的JDK8日期API中的一个类,它在ISO-8601日历系统中提供了一个带有时区的日期时间。你应该检查一下
Oracle's explanation for new date format

t2a7ltrp

t2a7ltrp3#

16年前,我为 JavaWorld 杂志写了一篇题为What's Your Time Zone的文章,其中讨论了您在使用类java.util.Date时所描述的问题。为了“看到”java.util.Date类示例的值,必须将其转换为String。在java 1.8之前,这种转换总是也会考虑时区。这就是为什么在Java 1.8中引入了一个新的日期-时间API的原因之一。为Java 1.8及更高版本编写的新代码应该使用新的API。我相信你也应该考虑转换旧代码来使用新的API,如果可能的话。

相关问题