问题是Java Date对象不存储时区。该值始终使用UTC,并在给定的时区(通常是JVM的默认时区)中进行解析和格式化。
Oracle日期列也不带时区存储,但应该表示用户看到的日期。在99.99%的情况下,这意味着JVM默认时区中的日期。
因此,JDBC驱动程序采用UTC格式的时间戳/日期值,将其转换为默认时区,并将其保存到数据库中。
所以最终的问题是,为什么它是这样设计的?原因何在?
日期-时间处理是一个令人惊讶的复杂主题。我们对时间的直觉理解对我们作为程序员不利,使这个主题难以掌握。此外,旧数据库和旧类中糟糕的日期时间处理使这项工作更加混乱。
首先,避免与最早版本的Java捆绑在一起的糟糕的旧日期时间类。不要使用java.util.date
、java.util.Calendar
、java.sql.timestamp
或其他相关类。只使用java.time类。如果必须与尚未更新为java.time的旧代码进行接口,请调用添加到旧类中的新转换方法。
日期
被即时
替换。
不是真的。即时
(和日期
)始终使用UTC。modern和legacy类都表示自1970年第一个时刻以来的小数秒数,用UTC表示,1970-01-01T00:00:00Z。总是在UTC,容易的。
Oracle日期列也不带时区存储,
真的。
但应该表示用户看到的日期。在99.99%的情况下,这意味着JVM默认时区中的日期。
我不知道作者这么说是什么意思。我认为这是他们笨拙的说法,即任何类似于SQL标准时间戳而没有时区
的类型都只是按原样接受任何给定的日期或日期,而不试图在区域或偏移量之间进行调整。因此,如果您在2018年1月21日中午通过,它将存储一个相当于这个字符串2018-01-23t12:00
的值,而不考虑那是魁北克蒙特雷的中午还是印度加尔各答的中午(两个不同的时刻,相隔几个小时)。
因此,JDBC驱动程序采用UTC格式的时间戳/日期值,将其转换为默认时区,并将其保存到数据库中。
不按原样调整和保存值(UTC)到底有什么错?
JDBC驱动程序不应该对Oracle日期
或SQL标准时间戳类型的UTC进行任何调整,而没有时区
。
如果在2018-06-06t21:53z的两个用户,一个在魁北克,一个在印度,同时将他们自己狭隘的挂钟时间的当前时刻保存到SQL类型的列中,标准时间戳不带时区
或Oracle日期
,那么我们应该看到两行具有值:
值不同,因为美洲/蒙特利尔
比世界协调时晚4小时,而亚洲/加尔各答
比世界协调时早5个半小时,并且没有对时区进行调整。再次重复一下,这里存储的值只表示日期和一天中的时间,但没有任何时区上下文或从UTC偏移量,它们不表示时刻。
造成混乱的原因可能是,某些数据库(如Postgres)确实将传入的值调整为UTC for values标题为不同类型的列,即Timestamp WITH TIME Zone
类型(请注意WITH
与WITH
与WITH
)。Postgres和其他数据库使用任何传递的区域/偏移量信息调整为UTC值,然后丢弃区域/偏移量信息。因此,类型名有点用词不当,您可以将其视为与时区有关的timestamp
。
如果上面在2018-06-06T21:53z看到的这两个用户将当前时刻保存到带有时区timestamp类型的SQL标准列中,那么这两行将显示为:
- 2018-06-06T21:53Z
- 2018-06-06T21:53Z
末尾的
z
发音为zulu
,表示UTC。
instant
类以UTC表示时间线上的一个时刻,分辨率为纳秒(最多九(9)位小数分数)。
Instant instant = Instant.now() ; // Capture the current moment in UTC.
商店。
String sql = "INSERT INTO tbl ( event ) VALUES ( ? ) ;" ; // Writing a moment into a column of type `TIMESTAMP WTH TIME ZONE`.
myPreparedStatement.setObject( 1 , instant ) ; // As of JDBC 4.2 and later, we can directly exchange java.time objects with our database.
取回。
Instant instant = myResultSet.getObject( … , Instant.class ) ;
ZoneId z = ZoneId.of( "Asia/Kolkat" ) ;
ZonedDateTime zdt = instant.atZone( z ) ; // Same moment, same point on the timeline, different wall-clock time.
要了解更多信息,请参阅Oracle教程。并搜索堆栈溢出的许多例子和解释。规范是JSR310。
您可以直接与数据库交换java.time对象。使用符合JDBC4.2或更高版本的JDBC驱动程序。不需要字符串,也不需要
java.sql.*
类。
从哪里获得java.time类?
null
null
null
问题内容: 我目前正在使用当前习惯用法创建UTC DateTime对象 是否有任何默认方法,所以我可以使用默认构造函数创建基于UTC的DateTime对象,从而使其更加隐式? 问题答案: 如果您只想为joda时间设置默认时区,请使用。 如果要更改整个jvm使用的时区,请使用方法。只需确保将其设置为早,因为它可以按joda时间进行缓存。.. 引用: 默认时区来自系统属性user.timezone。如
问题内容: 是否可以使用NOW()将默认时间添加为10分钟? 我已经尝试过类似的方法: 但是,它不起作用。 问题答案: 我不认为你可以做到这一点。 在MySQL的文件指出: 数据类型规范中的DEFAULT value子句指示列的默认值。除一个例外,默认值必须为常数;否则为0。它不能是函数或表达式。例如,这意味着您不能将日期列的默认值设置为诸如NOW()或CURRENT_DATE之类的函数的值。唯一
问题内容: 有谁知道如何将JS dateTime转换为MySQL datetime?还有一种方法可以向JS日期时间添加特定的分钟数,然后将其传递给MySQL日期时间? 问题答案: 尽管JS确实拥有足够的基本工具来执行此操作,但它相当笨拙。
问题内容: 我的Grails应用程序中有以下代码行,用于将默认时区设置为UTC: 我有一个带有字段的实体: 然后创建并保存一个实例: 这会将它正确地保存为我的数据库(以UTC时间)。但是,当我尝试将其读回时: 时间戳将改为作为本地时间读回。因此,如果我的时区是+1 UTC并且当前本地时间是 12:34:56 BST ,将保存到数据库的时间是 11:34:56 ,但是当我读回它时,它将变成 11:3
问题内容: 我已经尝试过一百万种不同的方法,但是没有用。任何帮助将非常感激。 上面的方法不起作用。 基本上,我想做的是获取纪元时间并将其转换为澳大利亚时间。我的当地时间是+05.30,但是我当然不希望这成为促成这种转化的因素。 编辑- 当我运行您的确切代码时,输出 时代1318388699000 2011年10月12日星期三08:34:59 GMT + 05:30 12/10/2011 03:
嗨,我有一个android应用程序,使用返回Int(或Long)类型的时间戳。我想将其转换为人类阅读器日期时间(根据设备时区) 例如,1175714200转换为GMT:2007年4月4日星期三19:16:40 GMT您的时区:2007年4月5日,3:16:40 AM GMT 8:00 我使用这个函数进行转换,但似乎没有返回正确的结果(所有结果都像(15/01/1970 04:04:25),这是不正