我需要将数据库生成的日期(列值默认为 SYSDATE)与用时区记录的手写时间戳进行比较。这是我正在尝试的比较:
where trunc(updated, 'mi') >= to_timestamp_tz('2017-10-24 04:45 US/Pacific', 'YYYY-MM-DD HH24:mi TZR')
我假设转换为时区时间戳的字符串应该与日期相当。但是,这仅在数据库位于我自己的时区时才有效。否则,我必须手动将外部时间戳转换为数据库时区。例如,如果我在BST中,而数据库在EST中,我必须编写:
where trunc(updated, 'mi') >= to_timestamp_tz('2017-10-24 04:45 US/Pacific', 'YYYY-MM-DD HH24:mi TZR')
其中 04:45 = 10:45 - 6,6 是 BST 和 EST 之间的差异。这看起来绝对违反直觉,因为原始时间戳已记录在 PST 中,因此输入为美国/太平洋。谁能解释一下为什么需要这种转换?如果有人提出更好的解决方案,我将不胜感激。
您可以将 DATE 列强制转换为TIMESTAMP WITH TIME ZONE
值,如下所示:
WHERE
FROM_TZ(CAST(TRUNC(updated, 'mi') AS TIMESTAMP),
(SELECT TO_CHAR(SYSTIMESTAMP, 'TZR') FROM dual)) >= to_timestamp_tz('2017-10-24 04:45 US/Pacific', 'YYYY-MM-DD HH24:mi TZR')
但它也可以反过来工作,即将TIMESTAMP WITH TIME ZONE
转换为数据库时区的 DATE:
WHERE
TRUNC(updated, 'mi') >=
CAST(TO_TIMESTAMP_TZ('2017-10-24 04:45 US/Pacific', 'YYYY-MM-DD HH24:mi TZR') AT TIME ZONE (SELECT TO_CHAR(SYSTIMESTAMP, 'TZR') FROM dual) AS DATE)
SYDATE
以数据库服务器操作系统的时区(NOT DBTIMEZONE
)提供,因此您必须使用(SELECT TO_CHAR(SYSTIMESTAMP, 'TZR') FROM dual)
或在适当的情况下提供硬编码值。
如果任何用户使用其当前本地时区插入/更新任何updated
,则此方法将失败。在这种情况下,时区信息会丢失,无法恢复。
如果您在任何 oracle 客户端中运行此查询,您还可以通过运行来更改会话设置
更改会话集TIME_ZONE ='BST';
更改会话time_zone来自数据库列的所有日期值和传递的没有时区的时间戳值都将转换为 BST。
因此,它将确保比较在共同的时区进行