Oracle上与时区相关的systimestamp和时间戳比较

时间:2014-02-07 03:29:00

标签: oracle datetime plsql

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

查询:

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企业版11.2.0.3.0版 - 64位生产

2 个答案:

答案 0 :(得分:1)

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

  

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

答案 1 :(得分:0)

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
    ...