在调试期间,我以简单的示例结尾:
select convert(datetime, '2015-04-15 03:30:00') as ts
go
Apr 15 2015 03:30AM
(1 row affected)
select convert(int, datediff(second, '1970-01-01 00:00:00',
convert(datetime, '2015-04-15 03:30:00'))) as ts
go
1429068600
(1 row affected)
$ TZ=UTC date --date=@1429068600 +%F_%T
2015-04-15_03:30:00
当我从JDBC执行查询时,我得到2个不等于上面的结果!码:
String TEST_QUERY = "select convert(datetime, '2015-04-15 03:30:00') as ts";
PreparedStatement stmt2 = conn.prepareStatement(TEST_QUERY);
ResultSet rs = stmt2.executeQuery();
rs.next();
logger.info("getTimestamp().getTime(): {}", rs.getTimestamp("ts").getTime());
logger.info("getDate().getTime(): {}", rs.getDate("ts").getTime());
stmt2.close();
执行结果(我使用Coreutils
date
实用程序仔细检查了结果):=> getTimestamp().getTime(): 1429057800000
$ TZ=UTC date --date=@1429057800 +%F_%T
2015-04-15_00:30:00
=> getDate().getTime(): 1429045200000
$ TZ=UTC date --date=@1429045200 +%F_%T
2015-04-14_21:00:00
Official docs for date types and JDBC Java mapping不说结果差异...
我的程序在
GMT+03:00
时区执行,并且我有SQL Server 2008,并尝试从https://msdn.microsoft.com/en-us/sqlserver/aa937724.aspx使用JDBC驱动程序4.0和4.1我希望在所有情况下都能获得UTC时间戳(从1970年开始),这仅适用于我用于交互式调试查询的Linux ODBC
tsql
实用程序。WTF?
最佳答案
您的第一对查询计算的是该纪元(本地)日期本地午夜以来的秒数。这种差异在任何时区都是相同的,因此,当您将数据库时区设置为UTC并将先前确定的偏移量转换回时间戳时,在数字匹配的意义上,您将获得“相同”的日期和时间,但它们表示不同的绝对时间,因为它们相对于不同的TZ。
通过JDBC执行查询时,您正在数据库时区GMT + 03:00中计算Timestamp
。 java.sql.Timestamp
表示绝对时间,但表示为与该纪元之初的格林尼治标准时间(GMT)的偏差。 JDBC驱动程序知道如何进行补偿。因此,您记录的是1970-01-01 00:00:00 GMT+00:00
和2015-04-15 03:30:00 GMT+03:00
之间的时间差。getDate().getTime()
版本没有那么明确,但是看起来当您将时间戳记作为Date
检索时,会截断时间部分,而截断是相对于数据库时区执行的。此后,与其他情况类似,java.sql.Date.getTime()
返回从时期轮到最终绝对时间的偏移量。也就是说,它正在计算1970-01-01 00:00:00 GMT+00:00
和2015-04-15 00:00:00 GMT+03:00
之间的差异
这都是一致的。