Java JDBC:日期始终偏移两天

27

我正在使用Java JDBC将日期写入SQL Server 2008,然后读取它。
读取回来的日期始终比实际写入的日期早两天。

我使用准备好的语句插入包含日期字段的行。日期值由以下提供:

java.sql.Date todaysDate = new java.sql.Date(System.currentTimeMillis()) ;
System.out.println(todaysDate.toString()) // -> 2012-07-02
ps.setDate(8, todaysDate);

将日期写入数据库后,如果我运行以下命令,SQL服务器会显示正确的日期:

select date from table_name where date!=null // ->2012-07-02
如果我通过JDBC运行相同的查询,然后从结果集中检索日期值,可以使用什么方法?
java.sql.Date sqlDate = rs.getDate("date") ;
sqlDate.toString() // ->2012-06-30

插入的行是表中唯一一个具有非空日期的行,因此这似乎不是读取错误记录的情况。

我以为这应该是一个众所周知的问题,但通过谷歌搜索“两天偏移”问题,我能找到的唯一参考资料没有明确的答案。

有什么想法吗?

beeky(活在过去)


如果你使用preparedStatement,请勿从String转换或转换为String。将日期(或时间戳)对象传递给setDate。 - Denys Séguret
@dystroy - 我正在使用java.sql.Date对象来设置准备好的语句中的值。你是不是想说相反的,比如要使用字符串? - user903724
@jim garrison 两者将在同一时区,即东部标准时间/东部夏令时。 - user903724
@user903724:不,我刚才看错了。不要使用字符串。 - Denys Séguret
1
打印日期值的时间部分以查看确切的偏移量可能非常有趣。 - Jim Garrison
显示剩余5条评论
9个回答

22

有问题的JDBC驱动程序

结果发现问题出在微软的JDBC驱动程序上。我尝试了所有可能的日期类型和日期转换组合,但都没有成功。经过大量搜索(本应该最先这样做!),我在一个旧的SO帖子上看到一条评论,暗示问题出在来自Microsoft的版本3 JDBC驱动程序上。我下载了最新的驱动程序,即版本4.x,问题得以解决。

感谢所有曾经试图提供帮助的人。特别感谢Mike花费时间发布了解决方法。

-=beeky


很有趣,但我也遇到了Microsft JSBC 4驱动程序的同样问题,JTDS可以正常工作。 - Javasick
已从jdbc 4.0升级到4.1,问题得到了解决。JRE7版本。 - PST
我尝试了几个不同版本的MSSQL jdbc驱动程序,它们在通过JDBC与SQL Server 2016交互时都表现相同,每个驱动程序都会从日期、日期时间或datetime2(7)列中返回一个getDate、getTimestamp或getString值,这些值比插入的值少2天。 - J E Carter II

5

对于正在使用Maven的人,使用以下代码适配Java 8:

 <dependency>
    <groupId>com.microsoft.sqlserver</groupId>
    <artifactId>mssql-jdbc</artifactId>
    <version>6.2.1.jre8</version>
 </dependency>

正如所指出的,如果您使用旧版,则可能会遇到此问题,并且难以进行调试。


作为一个细微的事实(驱动程序版本号),增强了现有答案,似乎应该将其发布为评论或编辑其他答案。 - Basil Bourque

2
如果你正在使用MSSQL 2015,可以使用Sqljdbc41来解决这个问题。
 <!-- https://mvnrepository.com/artifact/com.microsoft.sqlserver/sqljdbc41 -->
<dependency>
    <groupId>com.microsoft.sqlserver</groupId>
    <artifactId>sqljdbc41</artifactId>
    <version>6.0.8112</version>
</dependency>

2

像 user903724 所说的那样,升级到版本 4 可以解决这个问题,但在我的情况下,当我使用 sqljdbc4-3.0.jar 时,这个问题仍然存在。但是当我将它更改为 sqljdbc42.jar 时,这个问题得到了解决。希望我的经验对您有所帮助。

sqljdbc42.jar下载。


2

最近遇到了这个问题几次,每次都让我很头疼,但是后来想起来,如果字段是日期类型的话会出现这种情况,将字段类型更改为datetime类型就可以解决问题。


1

当我们在使用Microsoft SQL中的日期数据类型时,会遇到此问题。我已经将其修复为将日期更改为日期时间。


0

我在使用Java 8的sqljdbc4时遇到了完全相同的问题。

一旦我不需要在应用程序中对该字段进行任何类型的比较,我就通过在查询中将该字段转换为以下形式来解决了这个问题:CAST(dbo.tblPwActividadeParticipanteDetalhe.Data AS VARCHAR(10))


0

我曾经遇到过完全相同的问题。当我使用Java 6运行环境而不是Java 7运行环境时,2天偏移就消失了。

因此,这可能也是JDBC版本4.1与JDBC 3驱动程序向后兼容性之间的差异。


0
你的问题是时区值(“GMT”)。
你需要在你的JDBC获取方法中引入以下操作:
Calendar gmt = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
PreparedStatement stmt = connection.prepareStatement(sql);
stmt.setDate(1, new Date(0)); // I assume this is always GMT
ResultSet rs = stmt.executeQuery();
rs.next();

//This will output 0 as expected
System.out.println(rs.getDate(1, gmt).getTime());

时区如何导致两天的差异?我可以看到国际日期变更线附近有一天的差异,但是两天呢? - Jim Garrison
Mike,你的例子是回答我的问题还是演示如何查看时区偏移量? - user903724
Mike,是的,我试过了,但说实话,我没有理解你的例子,所以可能做错了。new java.sql.Date(0)生成了一个年份为1969的日期。之后,我就没有再深入研究了。如果年份=1969告诉你我哪里做错了,请纠正我。 - user903724

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接