从Oracle数据库检索日期列时,如何忽略java进行的DST调整?

时间:2019-05-31 09:42:43

标签: java oracle datetime jdbc timezone

我有一个带有 Date 列的Oracle表。

+--------+-----------------------+
|  ID    | CURR_DATE             |       
+--------+-----------------------+                       
|   1    |2003-04-06 02:59:59    |
+--------+-----------------------+  

当我做

select * from tablename

在数据库控制台中,我获得了CURR_DATE的正确列值。

但是当我使用JDBC在Java程序中执行相同操作时,由于夏令时,时间向前移动了一个小时。这是一个解释它的链接。 https://www.timeanddate.com/time/change/usa/new-york?year=2003

所以我收到的值是2003-04-06 03:59:59 ,而不是2003-04-06 02:59:59

发生这种情况是因为DB和JVM在PST中并且PST遵循DST(如果我错了,请纠正我)

这是我的代码

String query="select * from tablename";         
PreparedStatement psmt = con.prepareStatement(query);
ResultSet results=psmt.executeQuery();
while(results.next()) {
    System.out.println(results.getString(2));
}

可以做些什么,以便results.getString()向我返回数据库中相同的值(无需任何调整)。

我希望它返回原始值2003-04-06 02:59:59 ,而不是调整后的值2003-04-06 03:59:59 >。

2 个答案:

答案 0 :(得分:2)

As @gord-thompson explained you should use an up to date ojdbc8 or ojdbc10, ideally 19.3 or 18.3, you can use these even if your database is 11.2g https://www.oracle.com/technetwork/database/enterprise-edition/jdbc-faq-090281.html#01_02

results.getObject(2, LocalDateTime.class)

Explanation

The issue is really with the implementation of the java.sql.Timestamp class. It represents the milliseconds since 1970-01-01 00:00:00 GMT and 2003-04-06 02:59:59 in JVM time zone, 2003-04-06 02:59:59 does not exist in JVM time zone so the parser is off by the DST change.

LocalDateTime is not bound to any time zone and just year-month-day-hour-minute-second-nano and therefore has no issues representing 2003-04-06 02:59:59 whatever the JVM time zone.

答案 1 :(得分:1)

tl; dr

java.time.LocalDateTime ldt = myResultSet.getObject( … , LocalDateTime.class ) ;

使用智能对象,而不是哑字符串

您将日期时间值存储在日期时间列中,因此请在Java中使用日期时间类型。当前,您正在使用字符串。

Oracle DATE类型仅保留日期和日期,没有任何时区或UTC偏移量的概念。因此,DATE列不能用于表示时刻。标准SQL中的等效项是TIMESTAMP WITHOUT TIME ZONE

例如,如果某行在今年1月23日中午在该列中存储了一个值,则我们知道如何知道这是东京中午,加尔各答中午,巴黎中午还是中午。蒙特利尔。这些不同的正午都发生在不同的时刻,相隔数小时。

Java中与Oracle DATE列匹配的适当类型为LocalDateTime。此类也缺少任何时区或从UTC偏移的概念。所以它不能用来代表一个时刻。但是,当您只有日期和时间而没有区域/偏移量时,这是适合您的课程。

JDBC 4.2和更高版本要求支持直接与数据库交换 java.time 对象。

LocalDateTime ldt = myResultSet.getObject( … , LocalDateTime.class ) ;

写数据。

myPreparedStatemen.setObject( … , ldt ) ;

通过用没有任何区域/偏移的类型的数据库列交换没有任何区域/偏移的Java对象,您将对区域/偏移没有任何疑问。但是请注意这种日期时间值的局限性:

  • 不是片刻,也不是时间表上的一点。
  • 含糊不清,可以解释为大约26-27小时(全球时区范围)内的许多潜在时刻中的任何时刻。

Table of date-time types in Java (both modern and legacy) and in standard SQL.