使用JDBC从Oracle数据库获取精确的时间戳。
使用JDBC从Oracle数据库获取精确的时间戳。
我需要在数据库中存储UTC日期时间。
我已经将指定时区中给定的日期时间转换为UTC。为此,我按照下面的代码进行操作。
我的输入日期时间是 "20121225 10:00:00 Z",时区是 "Asia/Calcutta"。
我的服务器/数据库(Oracle)在相同的时区(IST) "Asia/Calcutta" 上运行。
在特定时区中获取日期对象
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"); //此日期对象具有给定的时间和给定的时区 java.util.Date parsedDate = dateFormatLocal.parse(date + " " + timeZone.getDisplayName(false, TimeZone.SHORT)); if (timeZone.inDaylightTime(parsedDate)) { //我们需要重新解析,因为在解析之前我们不知道日期是否为夏令时... parsedDate = dateFormatLocal.parse(date + " " + timeZone.getDisplayName(true, TimeZone.SHORT)); } //将其赋值给java.sql.TimeStamp实例变量 obj.setTsSchedStartTime(new java.sql.Timestamp(parsedDate.getTime()));
存储到数据库中
if (tsSchedStartTime != null) { stmt.setTimestamp(11, tsSchedStartTime); } else { stmt.setNull(11, java.sql.Types.DATE); }
输出
数据库(Oracle)存储了相同的给定日期时间: "20121225 10:00:00
,而不是UTC。
我通过下面的SQL进行了确认。
select to_char(sched_start_time, 'yyyy/mm/dd hh24:mi:ss') from myTable
我的数据库服务器也在相同的时区 "Asia/Calcutta" 上运行。
它给我提供了以下外观:
Date.getTime()
不是在UTC中- 或者在存储到数据库时,时间戳带有时区影响
我在这里做错了什么?
还有一个问题:
timeStamp.toString()
是否像 java.util.date
一样以本地时区打印?而不是UTC?
问题的原因是java.sql.Timestamp类并不具有特定的时区信息,它只是java.util.Date和一个独立的纳秒值的组合。这个类没有时区信息,只是简单地保存自1970年1月1日00:00:00 GMT以来的毫秒数加上纳秒数。在PreparedStatement.setTimestamp(int parameterIndex, Timestamp x, Calendar cal)方法中,Calendar被驱动程序用来更改默认的时区,但Timestamp仍然以GMT时区保存毫秒数。JDBC驱动程序在如何使用Calendar方面的API不明确,不同的提供商似乎可以自由解释它,例如,我上次使用MySQL 5.5 Calendar时,驱动程序在PreparedStatement.setTimestamp和ResultSet.getTimestamp中都忽略了Calendar参数。
解决方法是使用java 8+版本。在Timestamp内部(因为它继承自java.util.Date),有一个calendar属性,它有一个zoneinfo属性,实际上包含时区信息。你仍然可以通过.getTime()方法获取UTC时间,因为Timestamp也保存了它,但它确实具有时区信息。
需要注意的是,它保存的是自1970年1月1日00:00:00 UTC以来的毫秒数,而不是GMT。GMT有夏令时调整。UNIX纪元是自1970年1月1日00:00 UTC以来的毫秒数。