【问题标题】:timezone-dependant systimestamp and timestamp comparison on OracleOracle 上与时区相关的 systimestamp 和时间戳比较
【发布时间】:2014-02-07 03:29:00
【问题描述】:

我遇到了一个奇怪的情况。有人可以解释为什么时间戳和时间戳之间的比较行为如下(它取决于会话时区......)。此外,输出值在所有情况下都是相同的。 看起来时间戳从会话中继承时区以进行比较,但打印时却没有?

查询:

alter session set time_zone = '-6:0';
select cast(systimestamp as timestamp), systimestamp, case when cast(systimestamp as timestamp) < systimestamp then 'timestamp < systm' else 'timestamp >= systm' end as cmp from dual;
alter session set time_zone = '1:0';
select cast(systimestamp as timestamp), systimestamp, case when cast(systimestamp as timestamp) < systimestamp then 'timestamp < systm' else 'timestamp >= systm' end as cmp from dual;

输出:

CAST(SYSTIMESTAMPASTIMESTAMP) SYSTIMESTAMP                        CMP              
----------------------------- ----------------------------------- ------------------
14/02/06 21:22:05,319973000   14/02/06 21:22:05,319973000 -06:00  timestamp >= systm 

session SET altered.
CAST(SYSTIMESTAMPASTIMESTAMP) SYSTIMESTAMP                        CMP              
----------------------------- ----------------------------------- ------------------
14/02/06 21:22:06,057183000   14/02/06 21:22:06,057183000 -06:00  timestamp < systm  

数据库位于 -6 时区。 Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64 位生产

【问题讨论】:

    标签: oracle datetime plsql


    【解决方案1】:

    看看这个: https://docs.oracle.com/cd/B12037_01/server.101/b10749/ch4datet.htm#1006334

    当您比较日期和时间戳值时,Oracle 会在进行比较之前将数据转换为更精确的数据类型。例如,如果将 TIMESTAMP WITH TIME ZONE 数据类型的数据与 TIMESTAMP 数据类型的数据进行比较,Oracle 将使用会话时区将 TIMESTAMP 数据转换为 TIMESTAMP WITH TIME ZONE。 转换日期和时间戳数据的优先顺序如下: 1. 日期 2. 时间戳 3. 带有当地时区的时间戳 4. 带时区的时间戳 对于任意一对数据类型,Oracle 将前面列表中编号较小的数据类型转换为编号较大的数据类型。

    【讨论】:

      【解决方案2】:

      SYSTIMESTAMP 返回 TIMESTAMP WITH TIME ZONE 数据类型。看起来 Oracle 将 TIMESTAMP 转换为 TIMESTAMP WITH TIME ZONE 数据类型以进行比较,实际上 Oracle 执行此操作:

      SELECT
          CASE 
          WHEN CAST(CAST(SYSTIMESTAMP AS TIMESTAMP) AS TIMESTAMP WITH TIME ZONE) < SYSTIMESTAMP 
              THEN 'timestamp < systm' 
              ELSE 'timestamp >= systm' 
          END AS cmp 
      FROM dual;
      

      对于转换需要 SESSION 时区,您可以使用以下查询进行检查:

      SELECT 
          EXTRACT(TIMEZONE_HOUR FROM CAST(CAST(SYSTIMESTAMP AS TIMESTAMP) AS TIMESTAMP WITH TIME ZONE)) AS TZ_HOUR
      FROM dual;
      

      您可以讨论这是否有意义。对于正确的转换,您最好使用FROM_TZ 函数,然后它就在您的控制之下。 SYSTIMESTAMP 返回 DB 时区的时间戳,所以正确的语句应该是这样的:

      SELECT FROM_TZ(LOCALTIMESTAMP, DBTIMEZONE), SYSTIMESTAMP, 
          CASE FROM_TZ(LOCALTIMESTAMP, DBTIMEZONE) < SYSTIMESTAMP THEN
          ...
      

      【讨论】:

        猜你喜欢
        • 2017-04-03
        • 1970-01-01
        • 2017-06-24
        • 2019-05-23
        • 2020-08-14
        • 2023-03-19
        • 2017-06-24
        • 2012-09-15
        • 2017-05-13
        相关资源
        最近更新 更多