关于使用 SESSIONTIMEZONE 的一点警告
您的第一个示例不是防弹的,因为会话时区可以设置为以下任一:
- 操作系统本地时区 (
'OS_TZ'
)
- 数据库时区 (
'DB_TZ'
)
- 与 UTC 的绝对偏移量(例如,
'-05:00'
)
- 时区区域名称(例如,
'Europe/London'
)
看看这里发生了什么:
SELECT SESSIONTIMEZONE, DBTIMEZONE FROM DUAL;
SESSIONTIMEZONE | DBTIMEZONE
+04:00 | +07:00
ALTER SESSION SET TIME_ZONE='Europe/Paris';
SELECT SESSIONTIMEZONE, DBTIMEZONE FROM DUAL;
SESSIONTIMEZONE | DBTIMEZONE
Europe/Paris | +07:00
在您的函数中解析“Europe/Paris”字符串将会变得更加困难......您应该使用该TZ_OFFSET
函数,以确保您始终获得相同的±HH:MM
格式。
ALTER SESSION SET TIME_ZONE='Europe/Paris';
SELECT DBTIMEZONE, SESSIONTIMEZONE, TZ_OFFSET(SESSIONTIMEZONE) FROM DUAL;
DBTIMEZONE | SESSIONTIMEZONE | TZ_OFFSET(SESSIONTIMEZONE)
+07:00 | Europe/Paris | +02:00
关于您的第二个解决方案
我想我更喜欢你的第二个解决方案。您可以通过使用CURRENT_DATE
而不是缩短它CAST(SYSTIMESTAMP AT TIME ZONE SESSIONTIMEZONE AS DATE)
,它们是等效的:
SELECT (
CURRENT_DATE -
CAST(SYSTIMESTAMP AT TIME ZONE DBTIMEZONE AS DATE)
)*24
FROM DUAL;
从技术上讲,您甚至可以做到这一点!
SELECT (CURRENT_DATE - SYSDATE) * 24
FROM DUAL;
但实际上,SYSDATE
不能保证与DBTIMEZONE
. SYSDATE
始终绑定到底层操作系统的时区,而DBTIMEZONE
一旦服务器启动就可以更改。
而且我在扯皮的同时还要提醒你,某些国家/地区使用的偏移量不是整数,例如伊朗标准时间是UTC+03:30
,缅甸时间是UTC+06:30
......我不知道你是否会遇到这在您的生产环境中,但我希望您对查询返回类似1.5
...的可能性感到满意