繁体   English   中英

Oracle的日期和时间没有通过JDBC进行夏令时

[英]Oracle's date and time without daylight savings via JDBC

发出以下SQL会通过PL / SQL,ODBC和JDBC生成不同的结果:

select sysdate from dual

在PL / SQL或ODBC上运行时,日期和时间是正确的。 在JDBC上,它少了一个小时。 它似乎没有考虑夏令时。

例如,在PL / SQL上,结果是2012-11-05 16:53:53.0 ,在JDBC上,它是2012-11-05 15:53:53.0

它只发生在某些数据库上。 更改数据库时区( select dbtimezone from dual )似乎不会影响结果。

该命令正在巴西执行。 原始GMT偏移为-03:00,因为夏令时,当前偏移为-02:00。

客户端JVM的时区数据库是最新的。

要诊断数据库中的“错误”结果,只需打印结果:

((OracleResultSet) statement.executeQuery("select sysdate from dual")).getTIMESTAMP(1).toString();

Oracle的TIMESTAMP toString方法不依赖于时区信息。 JVM的时区可能仅在创建TIMESTAMP之前影响结果,即在从网络读取并将其转换为Java中的表示时。

测试更改客户端和数据库服务器时间配置:

  • SYSDATE始终返回在数据库服务器中解析的日期/时间,客户端JVM的user.timezone选项和客户端的机器时间配置无关紧要。
  • 另一方面,使用两个时区信息解析获取SYSTIMESTAMP :看起来它从UTC服务器获取日期和时间,然后在客户端应用时区以获取本地日期和时间。

客户端运行Windows,服务器运行Linux。

为了让事情变得更奇怪,发出TO_CHAR也会产生错误的结果:

select TO_CHAR(SYSDATE, 'DD/MM/YYYY HH24:MI:SS') from dual
  • 直接在Oracle: 06/11/2012, 10:38:4906/11/2012, 10:38:4906/11/2012, 10:38:49
  • 关于Java: 06/11/2012 09:38:49

Oracle服务器:

[root@oracle1 ~]# cat /etc/sysconfig/clock
ZONE="America/Sao_Paulo"
UTC=false
ARC=false
[root@oracle1 ~]# echo $TZ

[root@oracle1 ~]# date
Tue Nov 13 14:58:38 BRST 2012
[root@oracle1 ~]#


[root@oracle2 ~]# cat /etc/sysconfig/clock
ZONE="America/Sao_Paulo"
UTC=false
ARC=false
[root@oracle2 ~]# echo $TZ

[root@oracle2 ~]#  date
Tue Nov 13 14:59:58 BRST 2012
[root@oracle2 ~]#

有什么想法吗? 我应该从数据库中收集哪些信息或配置来诊断和解决此问题?

简而言之,在Java Date选择oracle DATE本身就存在问题。 那是因为它们根本不同。 Oracle DATE是年,月,日,小时,分钟,秒的组合,没有任何时区信息,所以它可以是任何时区,有或没有夏令时 - Oracle不知道,因为该信息不包括在内在DATE

另一方面,Java Date基本上是自UTC 1/1/1900 00:00:00 UTC以来的毫秒数。

当Oracle DATE进入Java Date ,JDBC驱动程序只能猜测要应用的时区。 结果相当不可预测,尤其是当数据库中的数据使用与用户不同的时区时。

Java日期在格式化之前没有时区。

java日期在内部存储为long - 自1970年1月1日UTC午夜起经过的毫秒数。

查看java Date的时间,以及它报告的时区(但是你将其格式化),你可能会发现它等同于数据库中的时间。

您很可能在格式化日期时遇到问题 - 使用您期望的时区以外的时区。 我猜你在格式化时没有指定时区(使用默认值),或者只是使用Date的toString()方法。

如果您使用日历(calendar.setTime(日期)),您可以将'纪元时间'与特定时区结合使用,或者如果它适用于您,请使用默认时区。 您还可以查询日历的时区,如果默认的时区不正确,那么您确实需要调查计算机本身是否设置为错误的时区,或者该计算机上的java时区数据库是否有问题。 。

“在你格式化之前,Java日期没有时区。” 错了,它被定义为UTC。 ammoQ的原始答案是正确的。 数据库日期列没有时区,虽然它可以存储为自1970年1月1日午夜以来的毫秒,它没有被定义为UTC,它是您喜欢的任何时区(即,无论时区如何,当地时间相同)。

特别是,在转换为UTC中的Java Date时,JDBC使用JVM的默认时区。 因此,如果数据库存储2014年1月1日02:00,并且您的JVM是“America / Chicago”,那么您将获得相当于2014年1月1日02:00 CST的Java日期。 如果您的JVM是“America / New_York”,那么您将获得相当于美国东部时间2014年1月1日02:00的Java日期。 这是一个非常不同的时刻,一小时(3600000毫秒)不同,恰好相当于1/1/2014 01:00 CST,而不是02:00 CST。

但是,如果该时区符合夏令时,那么使用JVM时区的最大问题是每年在“重叠时间”内发生。 数据库将在周日回归时间01:30(美国时区)说,但01:30是白天时间的第一个,也就是切换回标准时间后的第二个? JDBC / JVM必须在这两个时刻之间任意选择。 我记得,我认为大多数JVM总是使用标准时间(第二个01:30)。 虽然在春季跳到夏令时期间,技术上并不存在02:30的时间,但我认为大多数JVM将在春天到夏令时之后的03:30假设。

尝试vm参数

-Duser.timezone=GMT-2

要么

-Duser.timezone=America/Sao_Paulo

Java有自己的时区设置,可能会影响Date对象的传输。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM