使用util.date并从浏览器给日期提供服务时间,然后保存到db并取回数据库时,与直接从服务设置zoneddatetime相比,日期时间有所不同。
任何帮助将不胜感激。
答案 0 :(得分:4)
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的上下文。
内部,它是自UTC 1970年1月的第一时刻的纪元参考日期1970-01-01T00:00:00Z起的毫秒数。
使事情复杂化:
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调整到某个时区。
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
zdt.toString():2019-02-28T04:32:43.366 + 09:00 [亚洲/东京]
关键概念:Instant
和ZonedDateTime
都代表同一时刻,时间轴上的同一同时点。它们的挂钟时间不同。例如,如果日本某人给冰岛某人打电话(一直使用UTC作为时钟),并且他们俩都抬头看着各自墙上挂着的时钟,他们会看到不同的时间,并且可能甚至每月日历上的另一个日期。相同的时刻,不同的时钟时间。
对于旧类,ZonedDateTime
的等效项是GregorianCalendar
,这是java.util.Calendar
的具体实现。确实,旧类GregorianCalendar
获得了用于转换to / from 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
。然后继续您的业务逻辑。 问题提到数据库工作。这是一个简短的摘要。搜索堆栈溢出以获取更多详细信息,因为已经处理了很多次。
从JDBC 4.2开始,我们可以直接与数据库交换 java.time 对象。使用PreparedStatement::setObject
和ResultSet::getObject
。无需再碰到可怕的java.sql.*
类,例如java.sql.Timestamp
。
您 也许可以交换Instant
,但是JDBC规范不需要这样做。规范反而要求OffsetDateTime
。
检索。
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
还有存储。
myPreparedStatement.setObject( … , odt ) ;
如果手头有一个Instant
,请使用常量OffsetDateTime
转换为ZoneOffset.UTC
。
OffsetDateTime odt = Instant.atOffset( ZoneOffset.UTC ) ;
要查看某个区域的挂钟时间,请应用ZoneId
。
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = odt.atZoneSameInstant( z ) ;
要将ZonedDateTime
存储到数据库,请转换为OffsetDateTime
。这会剥夺时区信息(该地区人民根据政客的决定,对过去,现在和将来进行的更改的历史记录),留下日期,时间和偏移量-from-UTC(小时-分钟-秒的数量)。
OffsetDateTime odt = zdt.toOffsetDateTime();
大多数数据库在UTC中为SQL标准类型TIMESTAMP WITH TIMESTAMP
的列存储时间。将OffsetDateTime
提交到数据库时,您的JDBC驱动程序很可能会将OffsetDateTime
中的偏移量调整为零小时-分钟-秒(以UTC本身为准)。但是我喜欢明确地这样做。它使调试更加容易,并且向读者展示了我对存储在UTC中的那一刻的理解。
OffsetDateTime odt = zdt.toOffsetDateTime().withOffsetSameInstant( ZoneOffset.UTC ) ;
答案 1 :(得分:1)
java.util.Date
是几乎不推荐使用的类,它为毫秒值提供了包装。它不提供有关时区的任何信息,也没有任何有用的方法,您应始终避免使用它。
ZonedDateTime
是新的JDK8
日期API中的类,该API在ISO-8601日历系统中提供带有时区的日期时间。您应该检查
答案 2 :(得分:1)
十六年前,我为 JavaWorld 杂志写了一篇名为What's Your Time Zone的文章,其中涉及您在使用类java.util.Date
时描述的问题。为了“查看”类java.util.Date
的实例的值,您必须将其转换为String
。在Java 1.8之前,此转换总是也考虑了时区。这就是为什么在Java 1.8中引入了新的Date-Time API的原因之一。为Java版本1.8及更高版本编写的新代码应使用新的API。我相信您也应该考虑将旧代码转换为使用新的API。