JDBC时间戳和日期GMT问题
我有一个JDBC Date列,如果ai使用getDate只是在2009年10月2日获得’ date ‘部分,但是如果我使用getTimestamp我得到完整的’ date ‘ 2009年10月2日13:56:78:890 。 这是我想要的。
但是,getTimestamp返回的’date’会忽略’GMT值,假设日期; 2009年10月2日13:56:78:890 ,我最终获得2009年10月2日15:56:78:890
我的日期在数据库中保存为+ 2GMT日期,但应用程序服务器在GMT上,即落后2小时
怎么还能按照现状,2009年10月2日13:56:78:890
编辑
我在客户端获得了GMT +2上的日期+2
这是MySQL中Timestamp和其他时间类型之间的区别。 时间戳以UTC时间_t保存为UTC,但其他类型按字面存储日期/时间而不包含区域信息。
当您调用getTimestamp()时,如果类型为时间戳,则MySQL JDBC驱动程序会将时间从GMT转换为默认时区。 它不会对其他类型执行此类转换。
您可以更改列类型或自行进行转换。 我推荐以前的做法。
您应该知道java.util.Date
(以及java.sql.Date
和java.sql.Timestamp
,它们是java.util.Date
子类)对时区一无所知,或者说,它们始终在世界标准时间。
java.util.Date
及其子类只不过是“自01-01-1970,UTC AM 12:00”以来的“毫秒数”容器。
要在特定时区中显示日期,请使用java.text.DateFormat
对象将其转换为字符串。 通过调用setTimeZone()
方法在该对象上设置时区。 例如:
Date date = ...; // wherever you get this from DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // Make the date format show the date in CET (central European time) df.setTimeZone(TimeZone.getTimeZone("CET")); String text = df.format(date);
前几天我遇到了类似的问题,其中时间组件从某些日期被截断。
我们将其缩小到Oracle驱动程序版本的差异。
在Oracle的常见问题解答中有一节关于此:
select sysdate from dual; ...while(rs.next())
在9201之前,这将返回:getObject for sysdate:java.sql.Timestamp <<<< getDate for sysdate:java.sql.Date getTimetamp for sysdate:java.sql.Timestamp
从9201开始,将返回以下内容
getObject for sysdate:java.sql.Date <<<<< getDate for sysdate:java.sql.Date >> no change getTimetamp for sysdate:java.sql.Timestamp >> no change
注意:java.sql.Date没有时间部分,而java.sql.Timestamp没有。
随着数据类型映射的这种更改,当JDBC驱动程序从8i / 9iR1升级到920x JBDC驱动程序时,某些应用程序将失败和/或生成不正确的结果。 为了保持兼容性并在升级后保持应用程序正常工作,提供了兼容性标志。 开发人员现在有一些选择:
- 使用oracle.jdbc.V8Compatible标志。
默认情况下,JDBC驱动程序不检测数据库版本。 要更改用于处理TIMESTAMP数据类型的连接属性的兼容性标志
‘oracle.jdbc.V8Compatible’
可以设置为“true”,驱动程序的行为与8i,901x,9 200(相对于TIMESTAMPs)的行为相同。
默认情况下,标志设置为“false”。 在OracleConnection构造函数中,驱动程序获取服务器版本并相应地设置兼容性标志。
java.util.Properties prop=newjava.util.Properties(); prop.put("oracle.jdbc.V8Compatible","true"); prop.put("user","scott"); prop.put("password","tiger"); String url="jdbc:oracle:thin:@host:port:sid"; Connection conn = DriverManager.getConnection(url,prop);
使用JDBC 10.1.0.x而不是connection属性,可以使用以下系统属性:java -Doracle.jdbc.V8Compatible = true …..注意:此标志是一个仅限客户端的标志,用于控制时间戳和日期映射。 它不会影响任何数据库function。
“2。 在相应处理Date和TimeStamp列数据类型时,使用set / getDate和set / getTimestamp。
9i服务器支持Date和Timestamp列类型DATE映射到java.sql.Date,TIMESTAMP映射到java.sql.Timestamp。
所以对于我的情况,我有这样的代码:
import java.util.Date; Date d = rs.getDate(1);
使用9i我得到一个java.sql.Timestamp(这是java.util.Date的子类)所以一切都很常规,我有我的小时和分钟。
但是使用10g,相同的代码现在得到一个java.sql.Date(也是java.util.Date的子类,所以它仍然编译)但是HH:MM是TRUNCATED !!。
第二个解决方案对我来说非常简单 – 只需用getTimestamp替换getDate就可以了。 我想这是一个坏习惯。
从这篇文章我得出结论,JDBC确实检索了时间戳的时区(我不认为MS SQL支持这一点,大多数Google结果指向Oracle)
当调用JDBC getTimeStamp方法时,它只获取‘毫秒 ‘部分,并使用服务器TimeZone创建一个Date对象,即GMT。
当这个Date对象呈现给我的客户端+2 GMT时,它会增加2小时,这是标准偏移量,这会导致额外的小时数。
我通过从我检索的日期中删除时间偏移来校正这一点,即转换为真正的GMT日期。
private Date convertDate(Date date1) throws ParseException { SimpleDateFormat sdfFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String dateStr = sdfFormatter.format(date1); SimpleDateFormat sdfParser = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); sdfParser.setTimeZone(TimeZone.getTimeZone("GMT")); return sdfParser.parse(dateStr); }