执行 to_timestamp_tz() 时出现 ORA-01857

ORA-01857 when executing to_timestamp_tz()

为什么通过 SQLDeveloper 执行此查询以连接到我的数据库:

select to_timestamp_tz('05/22/2016 10:18:01 PDT', 'MM/DD/YYYY HH24:MI:SS TZD') from dual;

我收到以下错误:

ORA-01857: "not a valid time zone"
01857. 00000 -  "not a valid time zone"
*Cause:    
*Action:

但是,我能够直接从 sqlplus 在数据库所在的主机上执行查询而不会出现任何错误,得到预期的结果:

TO_TIMESTAMP_TZ('05/22/201610:18:01PDT','MM/DD/YYYYHH24:MI:SSTZD')
---------------------------------------------------------------------------
22-MAY-16 10.18.01.000000000 AM -07:00

所以,我想弄清楚我是否做错了什么。我读过该错误可能是由于一个时区的多个 tzabbrev 引起的,但这并不能解释为什么 sqlplus 正确运行查询,因为我可以看到不同的多个 tzabbrev主机和 SQLDeveloper 的时区(来自 v$timezone_names 的查询)。

真正的问题是我们的应用程序使用了这个查询,所以我们注意到这个问题有时会重现,即使应用程序部署在与数据库相同的主机上也是如此。

我在 sqldeveloper\sqldeveloper\bin\sqldeveloper.conf

中添加了 2 行
AddVMOption -Doracle.jdbc.timezoneAsRegion=false
AddVMOption -Duser.timezone=CET

这解决了问题。

已更新

To eliminate the ambiguity of boundary cases when the time switches from Standard Time to Daylight Saving Time, use both the TZR format element and the corresponding TZD format element

要在不更改 JVM 配置的情况下使您的查询正常工作,您应该提供时区区域

select to_timestamp_tz('05/22/2016 10:18:01 PDT US/Pacific', 'MM/DD/YYYY HH24:MI:SS TZD TZR') from dual;

因为您没有提供时区,所以会使用默认的时区。我们来看第一个参数'oracle.jdbc.timezoneAsRegion'。这由 jdbc 驱动程序定义如下:

CONNECTION_PROPERTY_TIMEZONE_AS_REGION

Use JVM default timezone as specified rather than convert to a GMT offset. Default is true.

因此,如果不定义此 属性,您将强制查询使用 属性 'user.timezone' 定义的默认时区。但实际上你还没有设置它。因此,解决方案是要么将 属性 'oracle.jdbc.timezoneAsRegion' 设置为 false(并且将使用数据库当前会话时区区域),要么隐式提供 'user.timezone' 属性