在Oracle中是否有一种顺畅的方法来获取当前时刻(当我执行调用时)SESSIONTIMEZONE和DBTIMEZONE之间的数字差异?
例如:
SELECT SESSIONTIMEZONE,DBTIMEZONE FROM DUAL;
返回:
+04:00 +07:00
所以,我需要一些函数,通过调用给定参数,我得到这两个值之间的差异.
对于上面的例子:
SELECT get_numeric_offset(SESSIONTIMEZONE,DBTIMEZONE) FROM DUAL;
将返回-3(标志是至关重要的).
当然,我可以自己编写这个函数,通过使用字符串并解析它们然后进行一些算术运算或做类似的事情(我仍然不认为这是一个非常流畅的解决方案:
SELECT ( CAST(SYSTIMESTAMP AT TIME ZONE SESSIONTIMEZONE AS DATE) - CAST(SYSTIMESTAMP AT TIME ZONE DBTIMEZONE AS DATE) )*24 FROM DUAL;
也许我错过了一些东西,Oracle实际上提供了一种计算两个给定时区之间差异的方法?
关于使用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之类的东西.