【问题标题】:java.sql.timestamp conversion to oracle array off by 1 hourjava.sql.timestamp 转换为 oracle 数组减少 1 小时
【发布时间】:2023-04-01 08:20:01
【问题描述】:

所以这是一个遗留系统。 Oracle 11g、java 1.7.0_291-b32、CentOS 7。 我有一个问题,时间减少了一个小时,并且整年都如此(这不仅仅是 DST 翻转的时候)。

这是使用 jdbc 调用具有本地时区数据类型的时区数组的 PL/SQL 过程的 java。请注意,这曾经是 100% 工作的。

所以一个 java.util.Date 数组被转换成一个 java.sql.Timestamp 数组。

   public static java.sql.Timestamp[] toTimestamp(Date [] objs) {
        java.sql.Timestamp[] tsArray = new java.sql.Timestamp[objs.length];
        int i=0;
        for(Date d : objs) {
            if(d == null)
                tsArray[i] = null;
            else
                tsArray[i] = new java.sql.Timestamp(((Date)d).getTime());
            i++;
        }

    return tsArray;
}

... 我已经确认返回的数组有正确的时间。 然后将数组转换为 oracle.sql.ARRAY 对象

ArrayDescriptor descriptor = ArrayDescriptor.createDescriptor( 'TIMEZONE_ARRAY', connection );      
        ARRAY oracleArray = new ARRAY(descriptor, connection, CollectionsUtil.toTimestamp(array) );

其中 'Timezone_Array' 是数据库中定义的类型,它是具有本地时区的时间戳数组。当转换发生在此处时,时间会从应有的时间调整一个小时。

为了解决这个问题。我首先要确保我的 jdbc 驱动程序是最新的可用于 jdk 7。我运行了 oracle 的时区更新工具,以确保 JDK/JRE 中的时区定义是最新的。我很困惑这怎么不对。

我在 11g 数据库中看到了类似的问题,我必须更新数据库的时区定义文件,此时它很好。我为 JRE 更新的时区信息是 2021a,所以应该没问题。感觉就像一个月前工作的那样,一些定义映射需要更新。 (为什么我更新了时区定义文件)无论如何,如果有人有建议,我会全力以赴。谢谢!

【问题讨论】:

  • 毫无疑问是时区问题。 JVM、数据库会话和数据库服务器的默认时区是什么?
  • 你如何检查“带有本地时区的时间戳”值,知道它们是一小时的休息时间?假定输入的时区是什么时区(以及附加到来自 Java 的时间戳的位置 - 在 Java 代码中,或者仅在数据到达数据库之后),以及您检查的会话的时区是什么结果?转换为“本地”时区之前的时区与从“本地”时区转换回会话时区后的时区之间的不匹配最有可能是罪魁祸首,而不是时区文件。
  • 您可以使用SELECT DBTIMEZONE FROM dual;查询数据库时区(与UTC的偏移量)
  • 所以。 jboss 服务器的时区是 Los_Angeles,数据库也是。 java中的会话,在这种情况下,用户是NewYork,时区设置为那个。因此,假设我正在安排一个重复发生的事件,该事件每天从美国东部标准时间中午开始,例如发生 10 次。在java中构造了一个时间戳数组,我附在Jboss服务器上单步执行代码,我可以看到时间实际上是中午。在代码将数组设置为传递给 oracle 的情况下,我在将该数组传递给数据库之前对其进行检查。休息 1 小时。
  • 所以 java 时间戳数组很好,但是当使用该时间戳数组初始化“带有本地时区的时间戳表”类型的 Oracle 数组时,时间会被破坏。多年来一直运行良好,直到最近..

标签: java arrays oracle jdbc timestamp


【解决方案1】:

所以。没有简单的方法来总结这一点。 我正在处理 dbtimezone --> Oracle 的默认时区,它是 GMT 的偏移量(或应该是)。 我的 jvm 时区可以基于系统环境(我的应用程序基于配置条目)。 登录到我的系统的用户有他们所在的特定时区,并且他们的会话设置为反映这一点。 为此,我们使用了带有本地时区的 oracle 时间戳。它将日期/时间存储在时区(请参阅 dbtimezone)时间中,而没有关于它的时区信息。 Oracle 将使用您配置的连接时区,并自动调整显示给用户的时区时间。 最重要的是,这是在 Java 7 中,并且大部分使用蹩脚的 java.util.Date。 直到今年,整个系统在过去十年中完美运行。 首先关。我必须更新 RDBMS 的时区信息。这修复了所有时区作为单例传递的问题。但是,它没有修复传递的相同类型的数组。 我的工作是使用 oracle 的 to_timestamp_tz 并传递一个字符串数组。使用 SimpleFormater 的 java.util.Date 字符串表示可以显示时区。我知道那个日期是不知道时区的。但是我的会话 IS 配置了时区,当你拉出字符串时会反映这一点。 (并且存储在日期中的时间是时区适用时间)。 由于 jdbc/java 拒绝了所有让它不延迟的尝试(它正在将时间更改为 dbtimezone 但没有正确执行 ti,所以我只是将这个字符串和 PL/SQL 过程传递给 to_timestamp_tz将其放在具有本地时区字段的时区中。 Oracle 可以顺利地将其从 to_timestamp_tz 中表示的时区更改为数据库的时区。 所以我没有修复代码,而是围绕错误进行编码。 所以一个简单的方法来获取日期数组并返回一个字符串数组。

public static String[] toTimestampString(Date [] objs, String timestampPattern) {
    int i=0;
    String[] tsArray = new String[objs.length];
    Format formatter = new SimpleDateFormat(timestampPattern);
    for (Date d: objs) {
        if (d == null) 
            tsArray = null;
        else {
            tsArray[i] = formatter.format(d);
            i++;
        }
            
    }
    return tsArray;
}

这个数组然后被传递到 PL/SQL 中,它基本上是这样做的:to_timestamp_tz(p_start_datetime(i),timestampPattern)

oracle 中的 timestampPattern 在 java 中略有不同,基本上在 java 中是“yyyy-MM-dd HH:mm XXX” 在 PL/SQL 中是:'yyyy-MM-dd HH24:mi tzr' 但他们的意思是一样的。我已经在大约 6 个不同的用户时区夏令时和 AZ 以及其他非夏令时进行了测试,并且它工作 100%。 thx 希望这能帮助其他被困在时区地狱中的可怜的灵魂。

【讨论】:

  • 一个问题。确保为时区偏移量指定所有 3 个“X”
猜你喜欢
  • 2016-08-18
  • 1970-01-01
  • 2012-06-27
  • 2015-12-07
  • 2018-10-29
  • 2013-05-26
  • 2013-01-27
  • 2012-09-12
  • 1970-01-01
相关资源
最近更新 更多