关于使用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
等内容的可能性...
tz_offset
,也知道有一些时区不是整数。我会为您的回答投票支持,但它并不完全回答了我的问题。 - whatsupbros