A little warning on using SESSIONTIMEZONE
Your first example is not bullet-proof, as the session time zone can be set to either of the following :
- Operating system local time zone (
'OS_TZ'
) - Database time zone (
'DB_TZ'
) - Absolute offset from UTC (for example,
'-05:00'
) - Time zone region name (for example,
'Europe/London'
)
Just look at what happens here :
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
Parsing that 'Europe/Paris' string in your function is going to be a lot harder... You should use the TZ_OFFSET
function, to ensure that you always get the same ±HH:MM
format.
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
About your second solution
I think I like your second solution better. You can shorten it by using CURRENT_DATE
instead of CAST(SYSTIMESTAMP AT TIME ZONE SESSIONTIMEZONE AS DATE)
, they are equivalent :
SELECT (
CURRENT_DATE -
CAST(SYSTIMESTAMP AT TIME ZONE DBTIMEZONE AS DATE)
)*24
FROM DUAL;
You could technically even do this !
SELECT (CURRENT_DATE - SYSDATE) * 24
FROM DUAL;
BUT actually, SYSDATE
is not guaranteed to be on the same timezone as DBTIMEZONE
. SYSDATE
is always bound to the underlying OS' timezone, while DBTIMEZONE
can be altered once the server has been started.
And while I'm splitting hairs, I should also remind you that certain countries / regions use offsets that are not whole numbers, for example Iran Standard Time is UTC+03:30
, Myanmar Time is UTC+06:30
... I don't know if you'll ever encounter this in your production environment, but I hope you're okay with the possibility that your query returns something like 1.5
...