JDBC 时间戳和日期 GMT 问题
Posted
技术标签:
【中文标题】JDBC 时间戳和日期 GMT 问题【英文标题】:JDBC Timestamp & Date GMT issues 【发布时间】:2010-12-03 07:10:31 【问题描述】:我有一个 JDBC 日期列,如果使用 getDate 则仅获取 'date' 部分 02 Oct 2009 但如果我使用 getTimestamp,我将得到完整的日期'2009 年 10 月 2 日 13:56:78:890。这正是我想要的。
但是,getTimestamp 返回的“日期”“忽略”了 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
【问题讨论】:
【参考方案1】:您应该知道java.util.Date
(以及java.sql.Date
和java.sql.Timestamp
,它们是java.util.Date
的子类)对时区一无所知,或者更确切地说,它们始终使用UTC。
java.util.Date
及其子类只不过是“自 1970 年 1 月 1 日凌晨 12:00 UTC 以来的毫秒数”值的容器。
要显示特定时区的日期,请使用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);
【讨论】:
【参考方案2】:这就是 Timestamp 和 mysql 中其他时间类型的区别。时间戳以 UTC 格式保存为 Unix time_t,但其他类型在没有区域信息的情况下直接存储日期/时间。
当您调用 getTimestamp() 时,如果类型是时间戳,MySQL JDBC 驱动程序会将时间从 GMT 转换为默认时区。它不会对其他类型执行此类转换。
您可以更改列类型或自行进行转换。我推荐前一种方法。
【讨论】:
关键字converts,这就是我得到+2小时的原因 我很困惑,如果转换工作正常,他不应该看到一个减少 2 小时而不是更多的日期吗? 这已经足够接近并引导我找到最终解决方案【参考方案3】:从post 我得出的结论是 JDBC 确实检索了时间戳的时区(我认为 MS SQL 也不支持这一点,大多数 Google 结果指向 Oracle)
当调用 JDBC getTimeStamp 方法时,它只获取 '毫秒' 部分并使用服务器 TimeZone 创建一个 Date 对象,即 GMT。
当这个 Date 对象呈现给我的客户(格林威治标准时间 +2)时,它会增加 2 小时,这是导致额外小时数的标准偏移量。
我已通过删除我检索到的日期的时间偏移来纠正此问题,即转换为真正的 GMT 日期。
【讨论】:
【参考方案4】:前几天我遇到了一个类似的问题,时间部分从某些日期被截断。
我们将其缩小到 Oracle 驱动程序版本的差异。
在 Oracle 的常见问题解答中有一个关于此的部分:
select sysdate from dual; ...while(rs.next())
在 9201 之前,这将返回: sysdate 的 getObject:java.sql.Timestamp
从 9201 开始,将返回以下内容
系统日期的getObject:java.sql.Date > 没有变化 getTimetamp for sysdate :java.sql.Timestamp >> 没有变化
注意:java.sql.Date 没有时间部分,而 java.sql.Timestamp 有。
随着数据类型映射的这一变化,当 JDBC 驱动程序从 8i/9iR1 升级到 920x JBDC 驱动程序时,某些应用程序将失败和/或生成错误的结果。 为了保持兼容性并在升级后保持应用程序正常工作,提供了一个兼容性标志。开发者现在有一些选择:
-
使用 oracle.jdbc.V8Compatible 标志。
JDBC Driver 默认不检测数据库版本。要更改处理 TIMESTAMP 数据类型的兼容性标志,连接属性
'oracle.jdbc.V8Compatible'
可以设置为“true”,并且驱动程序的行为与其在 8i、901x、9 200 中的行为相同(相对于 TIMESTAMP)。
默认情况下,该标志设置为“假”。在 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 中,可以使用以下系统属性来代替连接属性:java -Doracle.jdbc.V8Compatible=true.....注意:此标志是一个仅用于管理的客户端标志时间戳和日期映射。它不会影响任何数据库功能。
'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 被截断了!!。
第二个解决方案对我来说非常简单 - 只需将 getDate 替换为 getTimestamp 就可以了。我想那是个坏习惯。
【讨论】:
【参考方案5】: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);
【讨论】:
以上是关于JDBC 时间戳和日期 GMT 问题的主要内容,如果未能解决你的问题,请参考以下文章