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.Datejava.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 问题的主要内容,如果未能解决你的问题,请参考以下文章

js实现的时间戳和时间日期的转换

php时间戳和日期转换,以及时间戳和星期转换

时间戳和日期转换

如何查找当前时间戳和登录日期之间的天数 [重复]

Python 时间戳和日期相互转换

PHP时间戳和日期相互转换