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

Viv*_*mar 0 java datetime java.util.date zoneddatetime

在使用util.date并从浏览器给日期提供服务时间,然后保存到db并取回它时,与直接从服务中设置zoneddatetime相比,它提供了不同的日期时间。

任何帮助,将不胜感激..

Bas*_*que 8

tl; dr

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

  • Date代表UTC时刻,而ZonedDateTime代表特定时区的时刻。
  • Date是一个可怕的类,充满设计缺陷,永远不要使用,而它ZonedDateTimejava.time包中的一个现代类,您会发现它非常有用。

Java带有两个非常不同的用于处理日期时间工作的框架:一组尴尬且失败的遗留类集,以及在java.time包中找到的一组业界领先的现代类。

旧版?现代:

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

Java中用于日期时间处理的旧式和现代类的表格

java.util.Date

Date课程代表UTC的时刻。即,日期,一天中的时间以及UTC的上下文。

在内部,它是自UTC 1970-01-01T00:00:00Z的1970年第一时刻的纪元参考日期以来的毫秒数。

使事情复杂化:

  • 创建时有一个时区捕获,存储在内部,没有getter或setter。因此,尽管它确实适用于此类实现的问题,但在大多数情况下我们可以忽略此区域equals
  • 调用toString此类时,在生成表示该对象值的文本时动态地应用JVM的当前时区具有非常令人困惑的行为。尽管有很好的意图,但这种反功能在试图学习日期时间处理的Java程序员中造成了难以估量的痛苦。

困惑?是的,这堂课令人迷惑,糟糕的设计决策混乱不堪。后来又添加了java.util.CalendarGregorianCalendar

与最早的Java版本捆绑在一起的所有这些麻烦的日期时间类现在都完全被java.time类所取代。

特别java.util.Date是被代替java.time.Instant。从1970年UTC时代开始,两者都代表UTC的时刻。但是,Instant它具有更好的分辨率,即纳秒而不是毫秒

您可以通过调用添加到旧类中的新方法来在旧类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). 
Run Code Online (Sandbox Code Playgroud)

参见IdeOne.com实时运行代码。注意不同的日期和不同的时间,但同时具有相同的时刻。

Instant.toString():2019-02-27T19:32:43.366Z

zdt.toString():2019-02-28T04:32:43.366 + 09:00 [亚洲/东京]

关键概念:InstantZonedDateTime都表示同一时刻,在时间轴上的相同点同时进行。它们的挂钟时间不同。例如,如果日本某人给冰岛某人打电话(一直使用UTC作为时钟),并且他们俩都抬头看着挂在各自墙上的时钟,他们会看到不同的时间,并且可能甚至每月日历上的另一个日期。相同的时刻,不同的时钟时间。

至于传统类,等效的ZonedDateTimeGregorianCalendar,具体实现的java.util.Calendar。事实上,老班GregorianCalendar获得了转换的新方法 / ZonedDateTime

ZonedDateTime zdt = myGregorianCalendar.toZonedDateTime();  // Convert from legacy to modern class.
Run Code Online (Sandbox Code Playgroud)

…和…

GregorianCalendar gc = GregorianCalendar.from( zdt ) ;      // Convert from modern to legacy class.
Run Code Online (Sandbox Code Playgroud)

结论

因此,a Date等于a Instant,两者都是UTC中的时刻。但是ZonedDateTime两者的不同之处在于,时区通过应用区域人民的挂钟时间调整镜头来调整了对瞬间的感知。

提示:

  • 永远不要使用Date交到时Date,立即转换为Instant。然后继续您的业务逻辑。
  • 在UTC中完成大部分工作。跟踪时刻,调试,日志记录,交换日期时间值以及持久保存到数据库通常应该在UTC中完成。学会在从事程序员工作时忘记自己的时区。将您桌上的第二个时钟设置为UTC。

数据库

该课题提到数据库工作。这是一个简短的摘要。搜索堆栈溢出以获取更多详细信息,因为已经处理了很多次。

从JDBC 4.2开始,我们可以直接与数据库交换java.time对象。使用PreparedStatement::setObjectResultSet::getObject。无需再碰到java.sql.*诸如的可怕类java.sql.Timestamp

也许可以交换,Instant但JDBC规范不要求这样做。规范反而要求OffsetDateTime

恢复。

OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
Run Code Online (Sandbox Code Playgroud)

和存储。

myPreparedStatement.setObject( … , odt ) ;
Run Code Online (Sandbox Code Playgroud)

如果您Instant手头上有,请转换为OffsetDateTime使用常量ZoneOffset.UTC

OffsetDateTime odt = Instant.atOffset( ZoneOffset.UTC ) ;
Run Code Online (Sandbox Code Playgroud)

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

ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = odt.atZoneSameInstant( z ) ;
Run Code Online (Sandbox Code Playgroud)

要将a存储ZonedDateTime到数据库,请转换为OffsetDateTime。这会剥夺时区信息(该地区人民根据政客的决定对过去,现在和将来进行的更改的历史记录),留下日期,日期和偏移量-from-UTC(小时-分钟-秒的数量)。

OffsetDateTime odt = zdt.toOffsetDateTime(); 
Run Code Online (Sandbox Code Playgroud)

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

OffsetDateTime odt = zdt.toOffsetDateTime().withOffsetSameInstant( ZoneOffset.UTC ) ; 
Run Code Online (Sandbox Code Playgroud)


Bye*_*Bye 1

java.util.Date是一个几乎已弃用的类,它提供了毫秒值的包装器。它不提供任何有关时区的信息,没有任何有用的方法,您应该始终避免使用它。

ZonedDateTime是新日期 API 中的一个类JDK8,它提供 ISO-8601 日历系统中的日期时间和时区。你应该检查一下

Oracle对新日期格式的解释