关于使用 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...的可能性感到满意