Oracle / JDBC:以ISO 8601格式检索TIMESTAMP WITH TIME ZONE值
问题内容:
关于该主题的某些部分已经说了很多(并用SO写过),但没有以一种全面,完整的方式进行,因此我们可以有一个“最终的,涵盖所有方面的”解决方案供所有人使用。
我有一个Oracle数据库,用于存储全局事件的日期+时间+时区,因此必须保留原始TZ,并根据请求将其交付给客户端。理想情况下,通过使用标准ISO 8601“
T”格式可以很好地工作,该格式可以使用“ TIMESTAMP WITH TIME ZONE”列类型(“ TSTZ”)很好地存储在Oracle中。
类似于 “ 2013-01-02T03:04:05.060708 + 09:00”
我需要做的就是从数据库中检索以上值并将其发送给客户端,而无需进行任何操作。
问题在于Java缺乏对ISO 8601(或任何其他date + time + nano + 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会话格式设置(即,它忽略NLS_TIMESTAMP_TZ_FORMAT会话变量)。 -
JDBC的getObject()或getTIMESTAMPTZ()都返回Oracle的TIMESTAMPTZ对象,该对象实际上是无用的,因为它没有对Calendar的任何转换(仅日期,时间和时间戳),因此,我们再次丢失了TZ信息。
所以,这是我剩下的选项:
-
使用JDBC getString(),并对其进行字符串处理以修正并使其与ISO 8601兼容。这很容易做到,但是如果Oracle更改内部硬编码的getString()格式,就有死亡危险。另外,通过查看getString()源代码,似乎使用getString()也会导致性能下降。
-
使用Oracle DB“ toString”转换:“ SELECT TO_CHAR(tstz …)EVENT_TIME …”。效果很好,但有两个主要缺点:
- 现在,每个SELECT都必须包含TO_CHAR调用,这让人难以记住和编写
- 现在,每个SELECT都必须添加EVENT_TIME列“ alias”(例如,需要将结果自动序列化到Json)
。
-
使用Oracle的TIMESTAMPTZ Java类,并从其内部(已记录的)字节数组结构中手动提取相关值(即,实现我自己忘了在Oracle中实现的我自己的toString()方法)。如果Oracle(不太可能)更改内部结构并要求实施和维护相对复杂的功能,则存在风险。
-
我希望有第4个绝佳的选择,但是从整个Web和SO的角度来看-我看不到任何东西。
有想法吗?意见?
更新
下面给出了很多想法,但是似乎没有合适的方法来做到这一点。就我个人而言,我认为使用 方法1 是最短,最易读的方式(并保持良好的性能,
而又不会损失毫秒级或基于SQL时间的查询功能 )。
这是我最终决定使用的:
String iso = rs.getString(col).replaceFirst(" ", "T");
谢谢大家的良好回答,
B。
问题答案:
由于似乎没有神奇的方法可以做到这一点,因此最简单,最短的方法就是#1。具体来说,这就是所需的所有代码:
// convert Oracle's hard-coded: '2013-01-02 03:04:05.060708 +9:00'
// to properly formatted ISO 8601: '2013-01-02T03:04:05.060708 +9:00'
String iso = rs.getString(col).replaceFirst(" ", "T");
似乎只需添加“
T”就足够了,尽管一个完美主义者可能会放更多的化妆品(当然可以优化正则表达式),例如:rs.getString(col).replaceFirst(“”,“
T”)。replaceAll(“ “,”“).replaceFirst(” \ +([0-9])\:“,” + 0 $ 1:“);
B.