java - 甲骨文/JDBC : retrieving TIMESTAMP WITH TIME ZONE value in ISO 8601 format

标签 java database datetime jdbc timezone

关于该主题的某些部分已经说了很多(并写了 SO),但不是全面、完整的方式,所以我们可以有一个“终极、全面”的解决方案供每个人使用。

我有一个 Oracle 数据库,我在其中存储全局事件的日期+时间+时区,因此必须保留原始 TZ,并根据要求交付给客户端。理想情况下,它可以通过使用标准 ISO 8601“T”格式很好地工作,这种格式可以使用“TIMESTAMP WITH TIME ZONE”列类型(“TSTZ”)很好地存储在 Oracle 中。

类似'2013-01-02T03:04:05.060708+09:00'

我需要做的就是从数据库中检索上述值并将其发送给客户端,无需任何操作。

问题是 Java 缺乏对 ISO 8601(或任何其他日期+时间+纳米+tz 数据类型)的支持,情况更糟,因为 Oracle JDBC 驱动程序(ojdbc6.jar)对 TSTZ 的支持更少(而不是 Oracle DB 本身,它得到了很好的支持)。

具体来说,这是我不应该或不能做的事情:

  • 从 TSTZ 到 java 日期、时间、时间戳(例如通过 JDBC getTimestamp() 调用)的任何映射都将不起作用,因为我丢失了 TZ。
  • Oracle JDBC 驱动程序不提供任何将 TSTZ 映射到 java Calendar 对象的方法(这可能是一个解决方案,但目前没有)
  • JDBC getString() 可以工作,但 Oracle JDBC 驱动程序返回格式为
    '2013-01-02 03:04:05.060708 +9:00' 的字符串,这不符合 ISO 8601(没有“T ",TZ 中没有尾随 0,等等)。此外,这种格式在 Oracle JDBC 驱动程序实现中是硬编码的 (!),它也忽略了 JVM 语言环境设置和 Oracle session 格式设置(即它忽略了 NLS_TIMESTAMP_TZ_FORMAT session 变量)。
  • JDBC getObject() 或 getTIMESTAMPTZ() 都返回 Oracle 的 TIMESTAMPTZ 对象,这实际上是无用的,因为它没有任何到日历的转换(只有日期、时间和时间戳),所以再次,我们丢失了 TZ 信息.

所以,这里是我剩下的选项:

  1. 使用 JDBC getString() 并对其进行字符串操作以修复并使其符合 ISO 8601 标准。这很容易做到,但如果 Oracle 更改内部硬编码的 getString() 格式,就有死亡的危险。此外,通过查看 getString() 源代码,似乎使用 getString() 也会导致一些性能损失。

  2. 使用 Oracle DB“toString”转换:“SELECT TO_CHAR(tstz...) EVENT_TIME ...”。这工作正常,但有 2 个主要缺点:

    • 现在每个 SELECT 都必须包含 TO_CHAR 调用,这在内存和书写方面都令人头疼
    • 现在每个 SELECT 都必须添加 EVENT_TIME 列“别名”(例如需要将结果自动序列化为 Json)
      .
  3. 使用 Oracle 的 TIMESTAMPTZ java 类并从其内部(记录的)字节数组结构中手动提取相关值(即实现我自己的 toString() 方法,Oracle 忘记在那里实现)。如果 Oracle 更改内部结构(不太可能)并且需要相对复杂的功能来实现和维护,这是有风险的。

  4. 我希望有第 4 个选项,这是一个很好的选择,但是从整个网络来看,所以 - 我看不到任何选项。

想法?意见?

更新

下面给出了很多思路,但是好像没有合适的方法去做。就我个人而言,我认为使用方法 #1 是最短和最易读的方法(并且保持良好的性能,不会丢失亚毫秒或基于 SQL 时间的查询功能)。

这是我最终决定使用的:

String iso = rs.getString(col).replaceFirst(" ", "T");

谢谢大家的好回答,
B.

最佳答案

JDBC getObject(), or getTIMESTAMPTZ(), both return Oracle's TIMESTAMPTZ object, which is practically useless, because it doesn't have any conversion to Calendar (only Date, Time and Timestamp), so again, we lose TZ information.

这将是我的建议,因为这是获取所需信息的唯一可靠方式。

如果您使用的是 Java SE 8 并且拥有 ojdbc8,那么您可以使用 getObject(int, OffsetDateTime.class)。请注意,当您使用 getObject(int, ZonedDateTime.class) 时,您可能会受到 bug 25792016 的影响。 .

Use Oracle's TIMESTAMPTZ java class and extract relevant value manually from its internal (documented) byte array structure (i.e. implement my own toString() method which Oracle forgot to implement there). This is risky if Oracle changes internal structure (unlikely) and demands relatively complicated function to implement and maintain.

这就是我们ultimately went with直到 Oracle JDBC 驱动程序中提供无错误的 JSR-310 支持。我们确定这是获取所需信息的唯一可靠方式。

关于java - 甲骨文/JDBC : retrieving TIMESTAMP WITH TIME ZONE value in ISO 8601 format,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17559658/

相关文章:

java - SQL 异常 : java. sql.SQLException:未找到数据

java - 如何让 App Engine/Java 应用程序在来自 Java/Python 网络 cron 的无效请求下运行?

python - SQLite 在 WHERE LIKE 中的多个条件

mysql - SQL平均年龄比较函数返回null

r - 如何将日期和时间转换为数值

Java EAR - 类路径和库

java - Tomcat主页(地址:8080) redirects to website homepage

mysql - 关系中的 SQL 搜索

mysql索引大小和重复问题

php - Doctrine 和 DateTime 显示出错误的差异