【问题标题】:Oracle timezone offset differs when run in sqlplus vs sql developer在 sqlplus 与 sql developer 中运行时,Oracle 时区偏移量不同
【发布时间】:2021-07-13 22:18:35
【问题描述】:

这是一个谜题。获取以下查询并在 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”的结果。这给出了正确的 dst 调整时区偏移量(东部),其中一个日期在 dst,而另一个不在。从 sqlplus 运行相同的查询将两个值都设为“-4:00”。这会导致从 sqlplus 调用时也显示不正确值的包出现问题。

【问题讨论】:

  • 两个客户端的会话时区是什么? This is the same effect - 当然,并不是说您拥有这些价值观,但它们似乎有所不同。 (为什么要转换 sysdate,而不仅仅是使用 systimestamp?也许只是作为示例日期?)

标签: oracle oracle-sqldeveloper sqlplus


【解决方案1】:

当您转换为带有时区的时间戳时,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 Developer 从 Java 时区设置会话时区(默认从操作系统中获取;您可以通过 passing a user.timezone value at start-up 覆盖它)。 SQL*Plus uses the ORA_SDTZ environment variable,所以如果你不想在数据库中使用alter session(手动或通过login.sql)设置它,你可以设置它以匹配你的语言环境;如果未设置,则默认为“OS_TZ”:

ORA_SDTZ变量的默认值是'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 调整到不同的区域。

【讨论】:

  • 如果您要使用日期/时间组件(而不仅仅是时区组件),那么您希望使用 CURRENT_DATE 而不是 SYSDATE,因为您需要会话时间而不是您还使用SESSIONTIMEZONE时的系统时间。
  • 真;如果您确实只想要时区,也可以这样做,以防您碰巧在 DST 开关周围查看日期/时间。 (虽然我仍然认为 sydate/current_date 可能只是问题中真实日期的占位符......)
  • 如果它还解释了 OP 观察到的内容,答案会更清楚。您在原始帖子下方的问题中暗示了这一点。很可能,SQL Developer 会话的会话时区(保存在某处的设置中)是 'America/New_York'(然后是 DST 感知的),而 SQL*Plus 会话的默认会话时区是硬编码的 @987654340 @。我使用相同的界面,我不记得曾经搞乱这些设置,所以我必须有开箱即用的默认值;确实它们与我描述的相似(除了洛杉矶而不是纽约)。
【解决方案2】:

这给出了正确的 dst 调整时区偏移量(东部),其中一个日期在 dst,另一个不在。

不,它会为您提供一个看似正确的手动调整值;但是,当 DST 结束时,您的查询将不正确,需要调整……然后明年春天需要再次调整……明年秋天。

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-07-17
    • 1970-01-01
    • 2023-03-25
    • 2020-07-11
    • 1970-01-01
    • 2010-09-15
    • 1970-01-01
    • 2017-04-24
    相关资源
    最近更新 更多