java.util.Date和ZoneDateTime之间有什么区别?

java.util.Date和ZoneDateTime之间有什么区别?,java,datetime,java.util.date,zoneddatetime,Java,Datetime,Java.util.date,Zoneddatetime,当使用util.date并从浏览器中为日期和服务时间指定日期,然后保存到db并将其取回时,它会给出与直接从服务中设置zoneddatetime不同的日期时间 任何帮助都将不胜感激。java.util.Date是一个几乎不推荐使用的类,它提供了毫秒值的包装器。它不提供任何关于时区的信息,没有任何有用的方法,你应该避免使用它 ZonedDateTime是新JDK8日期API中的一个类,它在ISO-8601日历系统中提供带时区的日期时间。你应该检查一下 16年前,我为JavaWorld杂志写了一篇文章

当使用util.date并从浏览器中为日期和服务时间指定日期,然后保存到db并将其取回时,它会给出与直接从服务中设置zoneddatetime不同的日期时间

任何帮助都将不胜感激。

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

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


16年前,我为JavaWorld杂志写了一篇文章,题目是关于您在使用java.util.Date类时所描述的问题。为了查看java.util.Date类实例的值,必须将其转换为字符串。在Java1.8之前,这种转换也总是考虑时区。这就是为什么在Java1.8中引入了新的日期时间API的原因之一。为Java 1.8及以上版本编写的新代码应该使用新的API。我相信,如果可能的话,你也应该考虑转换旧代码来使用新的API。博士 java.util.Date和ZoneDateTime之间有什么区别

日期表示UTC中的一个时刻,而ZoneDateTime表示特定时区中的一个时刻。 Date是一个可怕的类,充满了设计缺陷,永远不应该使用它,而ZoneDateTime是java.time包中的一个现代类,您会发现它非常有用。 Java提供了两个非常不同的框架来处理日期时间工作:一组非常笨拙且失败的遗留类,以及在包中发现的一组现代业界领先的类

遗产➙ 现代:

java.util.Date被java.time.Instant替换 两者都代表UTC中的一个时刻。 java.util.GregorianCalendar被java.time.ZoneDateTime替换 两者都代表在特定时区中看到的一个时刻。 日期类型 Date类表示UTC中的一个时刻。也就是说,一天中的一个日期、一个时间,加上UTC的上下文

在内部,它是自1970年第一个时刻的纪元参考日期(UTC,1970-01-01T00:00:00Z)起的毫秒计数

使事情复杂化:

创建时有一个时区捕获,存储在内部深处,没有getter或setter。因此,在大多数情况下,我们可以忽略这个区域,尽管它确实适用于此类实现equals的问题。 当调用toString时,这个类有一个非常混乱的行为,即动态应用JVM的当前时区,同时生成文本来表示这个对象的值。尽管这是出于好意,但这个反功能在试图学习日期时间处理的Java程序员中造成了无法估量的痛苦。 困惑?是的,这门课令人困惑,糟糕的设计决策一团糟。后来又添加了java.util.Calendar和GregorianCalendar

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

特别是,java.util.Date被java.time.Instant替换。两者都表示从1970年UTC开始计算的UTC时刻。但瞬间的分辨率更高,而不是更高

通过调用添加到旧类中的新方法,可以在旧类Date和现代类Instant之间来回转换。通常,你会避免使用日期。但是当与尚未更新到java.time的旧代码交互时,您可能需要转换

java.time.zoneDateTime 现代阶级的ZoneDateTime代表了一个时刻,就像某个时区的人们在墙上使用的时钟一样

所以Instant和ZoneDateTime是相似的,它们都代表一个时刻,一个时间线上的特定点。不同之处在于ZoneDateTime知道时区的规则。因此,分区时间知道如何解释异常情况,如夏令时DST或政客要求的其他计时变化

你可以这样想:

ZoneDateTime=即时+区域ID

通过将时区ZoneId应用于即时对象,我们可以轻松地从UTC调整到某个时区

看这个。注意不同的日期和一天中不同的时间,但是相同的同时时刻

瞬变时间:2019-02-27T19:32:43.366Z

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

关键概念:Instant和ZoneDateTime都代表同一时刻,时间线上的同一个同时点。他们的挂钟时间不同。例如,如果日本有人给冰岛的人打电话,那里的时钟一直使用UTC,他们都会抬头看挂在各自墙上的时钟,他们会看到一天中不同的时间,甚至可能是不同的日期 日历。相同的时刻,不同的挂钟时间

至于遗留类,ZoneDateTime的等价物是的一个具体实现。事实上,旧类GregorianCalendar获得了转换/分区DateTime的新方法

……还有

GregorianCalendar gc = GregorianCalendar.from( zdt ) ;      // Convert from modern to legacy class.
结论 因此,日期相当于一个瞬间,两者都是UTC中的一个瞬间。但ZoneDateTime与两者的不同之处在于,时区通过应用一个地区的人们的挂钟时间调整镜头来调整对时刻的感知

小贴士:

永远不要使用日期。当收到日期时,立即转换为即时。然后继续您的业务逻辑。 在UTC中完成大部分工作。跟踪时刻、调试、日志记录、交换日期时间值以及持久化到数据库通常应在UTC中完成。当你在做程序员的时候,要学会忘记你自己的狭隘时区。在你的办公桌上保持第二个时钟设置为UTC。 数据库 问题涉及数据库工作。这里是一个简短的总结。搜索堆栈溢出以获取更多详细信息,因为这已被处理多次

从JDBC4.2开始,我们可以直接与数据库交换java.time对象。使用PreparedStatement::setObject和ResultSet::getObject。无需再接触可怕的java.sql.*类,如java.sql.Timestamp

您可能可以交换即时消息,但JDBC规范并不要求这样做。该规范要求使用OffsetDateTime

检索

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

myPreparedStatement.setObject( … , odt ) ;
如果您手头有一个瞬间,请转换为使用常量

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

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

OffsetDateTime odt = zdt.toOffsetDateTime(); 
大多数数据库以UTC为单位存储SQL标准类型TIMESTAMP和TIMESTAMP的列的时刻。将OffsetDateTime提交到数据库时,JDBC驱动程序可能会将OffsetDateTime中的偏移量调整为UTC自身的零小时分秒。但我喜欢明确地这样做。它使调试变得更容易,并向读者展示了我对存储在UTC中的时刻的理解

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

可能是@Michael的复制品不是真正的复制品。LocalDate对象只表示一个日期,没有一天中的时间和时区。相比之下,这里列出的Date和ZonedDateTime都代表一个时刻,而不仅仅是一个日期。@BasilBourque实际上有无数的问题组合,形式是类X和类Y之间的区别是什么。字符串和InputStream之间的区别是什么?Integer和ExpressionFieldProxyEventBroadcaster之间有什么区别?这个问题的核心概括在这里:我应该使用哪一个datetime库?@BasilBourque我的观点是,如果存在精确的文字匹配,这并不重要。如果这是标准,我们最终会得出:Date和LocalDate之间的区别是什么?Date和LocalDateTime之间有什么区别?日期和即时的区别是什么?日期和本地时间之间有什么区别?你明白了。通过迎合这种懒惰的问题,你并没有让好的信息更容易找到,你只是让它更破碎。我不理解你的设置,也不理解你想做什么。A,谢谢?答案是正确的,你应该避免使用Date类和friends,使用java.time,这是一个现代的日期和时间API。有一件事我不明白。在数据库中存储时,为什么要将ZoneDateTime转换为OffsetDateTime?我们可以轻松地将其存储为Instant+Offset,以便将其映射到时区类型为的SQL时间戳。@Martin该规范要求支持OffsetDateTime,但奇怪的是,不需要支持两种更常用的类型:Instant和ZoneDateTime。您的JDBC驱动程序可能支持也可能不支持其他两个类。如果是,您可以使用这些类型。如果您想编写更多可移植代码,请坚持使用OffsetDateTime。我将为这个答案添加一个带有粉色条纹的图表,显示JDBC4.2所需的类型。
OffsetDateTime odt = Instant.atOffset( ZoneOffset.UTC ) ;
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = odt.atZoneSameInstant( z ) ;
OffsetDateTime odt = zdt.toOffsetDateTime(); 
OffsetDateTime odt = zdt.toOffsetDateTime().withOffsetSameInstant( ZoneOffset.UTC ) ;