sqlplus 与 sql 开发人员中的 运行 时,Oracle 时区偏移量不同

Oracle timezone offset differs when run in sqlplus vs sql developer

这是一个益智游戏。采取以下查询并在 oracle sqldeveloper 中执行:

select to_char(CAST (sysdate AS  TIMESTAMP WITH TIME ZONE) ,'TZH:TZM') dst,    
           to_char(CAST (sysdate-160 AS  TIMESTAMP WITH TIME ZONE) ,'TZH:TZM') nodst    
 from dual;

您将得到“-04:00”、“-05:00”的结果。这给出了正确的夏令时调整后的时区偏移量(东部),其中一个日期在夏令时,另一个不在夏令时。 运行 来自 sqlplus 的相同查询将两个值都给出为“-4:00”。这导致包出现问题,从 sqlplus 调用时也显示不正确的值。

This gives the correct dst-adjusted timezone offset (eastern) with one date in dst, and the other not.

不,它给你一个看起来正确的手动调整值;但是,当 DST 结束时,您的查询将不正确,需要调整...然后下一个 spring 将需要再次调整...和明年秋天。

如果您想要正确的值,那么让 Oracle 调整时区(并且您不需要将 SYSDATE 转换为 TIMESTAMP WITH TIME ZONE,您可以只使用 SYSTIMESTAMPCURRENT_TIMESTAMP):

SELECT TO_CHAR(SYSTIMESTAMP AT TIME ZONE 'US/Eastern', 'TZH:TZM')
         AS timezone
FROM   DUAL

当您转换为带时区的时间戳时,Oracle 必须选择要使用的时区;它使用当前会话时区。这相当于做:

select to_char(FROM_TZ(CAST (sysdate AS  TIMESTAMP), SESSIONTIMEZONE) ,'TZH:TZM') dst,    
           to_char(FROM_TZ(CAST(sysdate-160 AS  TIMESTAMP), SESSIONTIMEZONE) ,'TZH:TZM') nodst    
 from dual;

由于您在 SQL Developer 和 SQL*Plus 中得到不同的结果,您似乎在这两个客户端中有不同的会话时区。您可以通过在每个中查询 sessiontimezone 来检查。 SQL 开发人员根据 Java 时区设置会话时区(默认情况下从操作系统中获取;您可以通过 passing a user.timezone value at start-up). SQL*Plus uses the ORA_SDTZ environment variable 覆盖它,因此您可以将其设置为与您的语言环境相匹配如果您不想使用 alter session(手动或通过 login.sql)从数据库中设置它;如果未设置,则默认为 'OS_TZ':

The default value of the ORA_SDTZ variable, which is used when the variable is not set or it is set to an invalid value, is 'OS_TZ'.

...并将其作为偏移量 (-04:00) 而不是区域。

如果无论任何用户的会话设置如何,您始终希望结果位于特定时区,那么您可以说明要使用哪个时区,例如:

select to_char(FROM_TZ(CAST (sysdate AS  TIMESTAMP), 'America/New_York') ,'TZH:TZM') dst,    
           to_char(FROM_TZ(CAST(sysdate-160 AS  TIMESTAMP), 'America/New_York') ,'TZH:TZM') nodst    
 from dual;

db<>fiddle 有几个要演示的会话设置。

大概您的真实查询是从可变日期值开始的,而不是 sysdate;否则,您可以使用 systimestamp,如有必要,使用 at time zone 调整到不同的区域。