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[亚洲/东京] 关键概念:Instant和ZonedDateTime都代表同一时刻,时间轴上同一个同时发生的点。他们在墙上的时钟时间不同。例如,如果一个在日本的人打电话给一个在冰岛的人(冰岛的时钟一直使用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.
大多数数据库为SQL标准类型TIMESTAMP WITH TIMESTAMP的列存储UTC时间。当将OffsetDateTime提交到数据库时,JDBC驱动程序可能会将OffsetDateTime中的偏移量调整为0小时-分钟-秒(UTC本身)。但我喜欢明确地这样做。它使调试更容易,并向读者展示了我对存储在UTC中的时刻的理解。
java.util.Date是一个几乎被弃用的类,它提供了一个围绕毫秒值的 Package 器。它不提供任何有关时区的信息,没有任何有用的方法,你应该永远避免使用它。 ZonedDateTime是新的JDK8日期API中的一个类,它在ISO-8601日历系统中提供了一个带有时区的日期时间。你应该检查一下 Oracle's explanation for new date format
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,如果可能的话。
3条答案
按热度按时间ijnw1ujt1#
tl;dr
java.util.Date和Zoneddatetime有什么区别?
Date
表示UTC中的时刻,而ZonedDateTime
表示特定时区中的时刻。Date
是一个糟糕的类,充满了设计缺陷,永远不应该使用,而ZonedDateTime
是一个来自 java.time 包的现代类,您会发现它非常有用。Java提供了两个非常不同的框架来处理日期时间工作:一组非常笨拙和失败的遗留类,以及一组在java.time包中找到的现代行业领先的类。
传统与现代:
java.util.Date
已替换为java.time.Instant
java.util.GregorianCalendar
已替换为java.time.ZonedDateTime
java.util.Date
Date
类表示UTC中的一个时刻。也就是说,一个日期,一天中的时间,加上UTC的上下文。在内部,它是自1970年第一时刻的历元参考日期(UTC,1970-01- 01 T00:00:00 Z)以来的毫秒计数。
更复杂的是:
equals
实现。toString
时,这个类有一个非常令人困惑的行为,即动态应用JVM的当前时区,同时生成文本来表示这个对象的值。虽然初衷是好的,但是这个反特性给试图学习日期时间处理的Java程序员带来了难以估量的痛苦。是的,这个类很混乱,一堆糟糕的设计决策。由后来添加的
java.util.Calendar
和GregorianCalendar
复合。所有这些与最早版本的Java捆绑在一起的麻烦的日期-时间类现在完全被 java.time 类所取代。
特别地,
java.util.Date
被java.time.Instant
替换。两者都表示从1970 UTC历元开始计数的UTC时刻。但Instant
的分辨率更高,为nanoseconds,而不是milliseconds。您可以通过调用添加到旧类的新方法,在遗留类
Date
和现代类Instant
之间来回转换。通常,您会避免使用Date
。但是当与尚未更新到 java.time 的旧代码交互时,您可能需要进行转换。java.time.ZonedDateTime
现代类
ZonedDateTime
表示某个地区(时区)的人们使用的挂钟时间中的某个时刻。所以
Instant
和ZonedDateTime
是相似的,它们都代表一个时刻,时间轴上的一个特定点。不同之处在于ZonedDateTime
知道时区的规则。因此,ZonedDateTime
知道如何解释诸如夏令时(DST)或政治家要求的其他计时更改等异常情况。你可以把它想成:
ZonedDateTime
=(Instant
+ZoneId
)我们可以通过将时区(
ZoneId
)应用到Instant
对象来轻松地从UTC调整到某个时区。看看这个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[亚洲/东京]
关键概念:
Instant
和ZonedDateTime
都代表同一时刻,时间轴上同一个同时发生的点。他们在墙上的时钟时间不同。例如,如果一个在日本的人打电话给一个在冰岛的人(冰岛的时钟一直使用UTC),他们都抬头看挂在各自墙上的时钟,他们会看到一天中不同的时间,甚至可能是月历上不同的日期。同样的时刻,不同的挂钟时间。至于遗留类,
ZonedDateTime
的等价物是GregorianCalendar
,它是java.util.Calendar
的具体实现。实际上,旧类GregorianCalendar
获得了新的方法来转换为ZonedDateTime
。还有...
总结
因此,
Date
相当于Instant
,两者都是UTC中的时刻。但ZonedDateTime
与两者的不同之处在于,一个时区通过应用一个地区的人们的挂钟时间调整的透镜来调整对时刻的感知。温馨提示:
***不要使用
Date
。**当拿到Date
时,立即转换为Instant
。然后继续你的商业逻辑。***大多数工作都是在UTC中进行的。**跟踪时刻、调试、日志记录、交换日期-时间值以及持久化到数据库通常都应该在UTC中进行。当你作为一个程序员工作时,要学会忘记你自己的时区。在你的办公桌上放一个时钟,设定为UTC。
数据库
问题提到数据库工作。下面是一个简短的总结。搜索堆栈溢出以获得更多细节,因为这已经被处理过很多次了。
从JDBC4.2开始,我们可以直接与数据库交换 java.time 对象。使用
PreparedStatement::setObject
和ResultSet::getObject
。再也不需要接触可怕的java.sql.*
类,如java.sql.Timestamp
。您可以交换
Instant
,但JDBC规范并不要求这样做。规范要求使用OffsetDateTime
。检索。
还有储藏室
如果你有一个
Instant
,使用常量ZoneOffset.UTC
转换为OffsetDateTime
。要通过某个区域的挂钟时间查看该时刻,请应用
ZoneId
。要将
ZonedDateTime
存储到数据库中,请转换为OffsetDateTime
。这将去除时区信息(过去、现在和未来对该地区人民使用的偏移量所做的更改的历史,这些更改由他们的政治家决定),留下日期、时间和UTC偏移量(小时-分钟-秒的数量)。大多数数据库为SQL标准类型
TIMESTAMP WITH TIMESTAMP
的列存储UTC时间。当将OffsetDateTime
提交到数据库时,JDBC驱动程序可能会将OffsetDateTime
中的偏移量调整为0小时-分钟-秒(UTC本身)。但我喜欢明确地这样做。它使调试更容易,并向读者展示了我对存储在UTC中的时刻的理解。yduiuuwa2#
java.util.Date
是一个几乎被弃用的类,它提供了一个围绕毫秒值的 Package 器。它不提供任何有关时区的信息,没有任何有用的方法,你应该永远避免使用它。ZonedDateTime
是新的JDK8
日期API中的一个类,它在ISO-8601日历系统中提供了一个带有时区的日期时间。你应该检查一下Oracle's explanation for new date format
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,如果可能的话。