是java.sql.Timestamp时区特定的?

我必须在数据库中存储UTC dateTime。
我已将特定时区中给定的date时间转换为UTC。 为此我遵循下面的代码。
我input的date时间是“20121225 10:00:00 Z”时区是“亚洲/加尔各答”
我的服务器/数据库(甲骨文)运行在相同的时区(IST)“亚洲/加尔各答”

获取此特定时区中的Date对象

String date = "20121225 10:00:00 Z"; String timeZoneId = "Asia/Calcutta"; TimeZone timeZone = TimeZone.getTimeZone(timeZoneId); DateFormat dateFormatLocal = new SimpleDateFormat("yyyyMMdd HH:mm:ss z"); //This date object is given time and given timezone java.util.Date parsedDate = dateFormatLocal.parse(date + " " + timeZone.getDisplayName(false, TimeZone.SHORT)); if (timeZone.inDaylightTime(parsedDate)) { // We need to re-parse because we don't know if the date // is DST until it is parsed... parsedDate = dateFormatLocal.parse(date + " " + timeZone.getDisplayName(true, TimeZone.SHORT)); } //assigning to the java.sql.TimeStamp instace variable obj.setTsSchedStartTime(new java.sql.Timestamp(parsedDate.getTime())); 

存入数据库

  if (tsSchedStartTime != null) { stmt.setTimestamp(11, tsSchedStartTime); } else { stmt.setNull(11, java.sql.Types.DATE); } 

OUTPUT

DB(oracle)已经存储了相同的dateTime: "20121225 10:00:00不是UTC。

我已经从下面的SQL确认。

  select to_char(sched_start_time, 'yyyy/mm/dd hh24:mi:ss') from myTable 

我的数据库服务器也运行在同一个时区“亚洲/加尔各答”

它给了我下面的外观

  1. Date.getTime()不是UTC
  2. 或时间戳是存在时区的影响,而存储到数据库我在这里做错了什么?

还有一个问题:

timeStamp.toString()打印在像java.util.date这样的本地时区java.util.date吗? 不是UTC?

虽然没有明确指定setTimestamp(int parameterIndex, Timestamp x)驱动程序必须遵循由setTimestamp(int parameterIndex, Timestamp x, Calendar cal) javadocbuild立的规则:

使用给定的Calendar对象将指定参数设置为给定的java.sql.Timestamp值。 驱动程序使用Calendar对象构造一个SQL TIMESTAMP值,然后驱动程序将其发送到数据库。 使用Calendar对象,司机可以计算考虑到自定义时区的时间戳。 如果没有指定Calendar对象,则驱动程序使用默认时区,即运行应用程序的虚拟机的时区。

当使用setTimestamp(int parameterIndex, Timestamp x)调用JDBC驱动程序时,将使用虚拟机的时区来计算该时区中的时间戳的date和时间。 此date和时间是存储在数据库中的内容,如果数据库列不存储时区信息,则有关该区域的任何信息都将丢失(这意味着由使用数据库的应用程序使用同一时区一致或想出另一个scheme来辨别时区(即存储在一个单独的列)。

例如:您当地的时区是GMT + 2。 您存储“2012-12-25 10:00:00 UTC”。 存储在数据库中的实际值是“2012-12-25 12:00:00”。 您再次检索它:您将它重新取回为“2012-12-25 10:00:00 UTC”(但仅当您使用getTimestamp(..)检索它时),但是当另一个应用程序访问时区GMT +0,它将检索时间戳为“2012-12-25 12:00:00 UTC”。

如果要将其存储在不同的时区,则需要在所需的时区中使用带有Calendar实例的setTimestamp(int parameterIndex, Timestamp x, Calendar cal) 。 只要确保在检索值时(如果在数据库中使用没有时区信息的TIMESTAMP也使用具有相同时区的等效getter。

所以,假设你想存储实际的GMT时区,你需要使用:

 Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT")); stmt.setTimestamp(11, tsSchedStartTime, cal); 

在JDBC 4.2中,兼容的驱动程序应该通过get/set/updateObject支持TIMESTAMP (和TIME )的java.time.LocalDateTime (和java.time.LocalTime )。 java.time.Local*类没有时区,所以不需要应用转换(尽pipe如果你的代码假设了特定的时区,这可能会引发一系列新的问题)。

我认为正确的答案应该是java.sql.Timestamp不是时区特定的。 Timestamp是java.util.Date和单独的纳秒值的组合。 此课程中没有时区信息。 因此,正如Date这个类只是保持自1970年1月1日00:00:00 GMT + nanos以来的毫秒数。

在PreparedStatement.setTimestamp(int parameterIndex,Timestamp x,Calendar cal)驱动程序使用日历来更改默认时区。 但时间戳仍然保持在毫秒为GMT。

API不清楚JDBC驱动程序应该如何使用Calendar。 提供者似乎对如何解释它是免费的,例如,上次我使用MySQL 5.5日历时,驱动程序在PreparedStatement.setTimestamp和ResultSet.getTimestamp中都忽略了日历。

这是来自你的驱动程序。 你需要在你的Java程序中提供一个参数来告诉它你想要使用的时区。

 java -Duser.timezone="America/New_York" GetCurrentDateTimeZone 

此外:

 to_char(new_time(sched_start_time, 'CURRENT_TIMEZONE', 'NEW_TIMEZONE'), 'MM/DD/YY HH:MI AM') 

在正确处理转换中也是有价值的。 从这里采取

对于Mysql,我们有一个限制。 在驱动程序Mysql文档中 ,我们有:

以下是MySQL Connector / J的一些已知问题和限制:Connector / J使用结果集上的getTimeStamp()方法检索夏令时(DST)切换日的时间戳时,某些返回的值可能是错误的。 连接到数据库时,可以通过使用以下连接选项来避免错误:

 useTimezone=true useLegacyDatetimeCode=false serverTimezone=UTC 

所以,当我们不使用这个参数,我们调用setTimestamp or getTimestamp日历或没有日历,我们有jvm时区的时间戳。

例如:

jvm时区是GMT + 2。 在数据库中,我们有一个时间戳: 1461100256 = 19/04/16 21:10:56,000000000 GMT

 Properties props = new Properties(); props.setProperty("user", "root"); props.setProperty("password", ""); props.setProperty("useTimezone", "true"); props.setProperty("useLegacyDatetimeCode", "false"); props.setProperty("serverTimezone", "UTC"); Connection con = DriverManager.getConnection(conString, props); ...... Calendar nowGMT = Calendar.getInstance(TimeZone.getTimeZone("GMT")); Calendar nowGMTPlus4 = Calendar.getInstance(TimeZone.getTimeZone("GMT+4")); ...... rs.getTimestamp("timestampColumn");//Oracle driver convert date to jvm timezone and Mysql convert date to GMT (specified in the parameter) rs.getTimestamp("timestampColumn", nowGMT);//convert date to GMT rs.getTimestamp("timestampColumn", nowGMTPlus4);//convert date to GMT+4 timezone 

第一种方法返回: 1461100256000 = 19/04/2016 – 21:10:56 GMT

第二种方法返回: 1461100256000 = 19/04/2016 – 21:10:56 GMT

第三种方法返回: 1461085856000 = 19/04/2016 – 17:10:56 GMT

当我们使用相同的调用时,而不是甲骨文,我们有:

第一种方法返回: 1461093056000 = 19/04/2016 – 19:10:56 GMT

第二种方法返回: 1461100256000 = 19/04/2016 – 21:10:56 GMT

第三种方法返回: 1461085856000 = 19/04/2016 – 17:10:56 GMT

注意:没有必要为Oracle指定参数。