使用JDBC从Oracle数据库获取精确的时间戳。

9 浏览
0 Comments

使用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" 上运行。

它给我提供了以下外观:

  1. Date.getTime() 不是在UTC中
  2. 或者在存储到数据库时,时间戳带有时区影响

    我在这里做错了什么?

还有一个问题:

timeStamp.toString() 是否像 java.util.date 一样以本地时区打印?而不是UTC?

0
0 Comments

问题的原因是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以来的毫秒数。

0