JDBC时间戳&日期GMT问题

时间:2009-10-02 11:30:30

标签: java sql jdbc gmt

我有一个JDBC Date列,如果ai使用getDate只获得' date '部分 2009年10月2日但是如果我使用getTimestamp我会得到满的' date ' 2009年10月2日13:56:78:890 。这是我想要的。

然而,getTimestamp返回的'date'会忽略'GMT值,假设为date; 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

5 个答案:

答案 0 :(得分:12)

这就是MySQL中Timestamp和其他时态类型之间的区别。时间戳以UTC时间整数保存为UTC,但其他类型按字面顺序存储日期/时间而不包含区域信息。

当您调用getTimestamp()时,如果类型为timestamp,则MySQL JDBC驱动程序会将时间从GMT转换为默认时区。它不会对其他类型执行此类转换。

您可以更改列类型或自行进行转换。我推荐以前的做法。

答案 1 :(得分:4)

您应该知道java.util.Date(以及java.sql.Datejava.sql.Timestampjava.util.Date的子类)对时区一无所知,或者更确切地说,它们是始终是UTC。

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);

答案 2 :(得分:3)

前几天我遇到了一个类似的问题,从某些日期开始截断时间组件。

我们将其缩小到Oracle驱动程序版本的差异。

在Oracle的常见问题解答中,有一节关于此:


select sysdate from dual; ...while(rs.next())

在9201之前,这将返回:     getObject for sysdate:java.sql.Timestamp<<<<     getDate for sysdate:java.sql.Date     sysdate的getTimetamp:java.sql.Timestamp

从9201开始,将返回以下内容

用于sysdate的getObject:java.sql.Date<<<<< getDate for sysdate:java.sql.Date>>没变 sysdate的getTimetamp:java.sql.Timestamp>>没有变化

注意:java.sql.Date没有时间部分,而java.sql.Timestamp则没有。

在数据类型映射中进行此更改时,当JDBC驱动程序从8i / 9iR1升级到920x JBDC驱动程序时,某些应用程序将失败和/或生成不正确的结果。 为了保持兼容性并在升级后保持应用程序正常工作,提供了兼容性标志。开发人员现在有一些选择:

  1. 使用oracle.jdbc.V8Compatible标志。
  2. 默认情况下,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而不是连接属性,可以使用以下系统属性: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是TRUNCATED !!。

    第二种解决方案对我来说非常简单 - 只需用getTimestamp替换getDate就可以了。我想这是一个坏习惯。

答案 3 :(得分:0)

从这个post我得出结论,JDBC确实检索了时间戳的时区(我不认为MS SQL支持这一点,大多数Google结果都指向Oracle)

当调用JDBC getTimeStamp方法时,它只获取 '毫秒 '部分并使用服务器TimeZone创建Date对象,是GMT。

当这个Date对象呈现给我的客户端+2 GMT时,它会增加2小时,这是标准偏移量,这会导致额外的小时数。

我已经通过删除我检索日期的时间偏移来校正这一点,即转换为真正的GMT日期。

答案 4 :(得分:0)

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);
    }