Oracle timezone offset differs when run in sqlplus vs sql developer - oracle

Here's a puzzler. Take the following query and execute in oracle sqldeveloper:
select to_char(CAST (sysdate AS TIMESTAMP WITH TIME ZONE) ,'TZH:TZM') dst,
to_char(CAST (sysdate-160 AS TIMESTAMP WITH TIME ZONE) ,'TZH:TZM') nodst
from dual;
you will get the results of "-04:00", "-05:00". This gives the correct dst-adjusted timezone offset (eastern) with one date in dst, and the other not. Running the same query from sqlplus gives both values as "-4:00". This is causing a problem for a package that when called from sqlplus shows the incorrect value also.

When you cast to a timestamp with time zone, Oracle has to choose which time zone to use; and it uses the current session time zone. It's equivalent to doing:
select to_char(FROM_TZ(CAST (sysdate AS TIMESTAMP), SESSIONTIMEZONE) ,'TZH:TZM') dst,
to_char(FROM_TZ(CAST(sysdate-160 AS TIMESTAMP), SESSIONTIMEZONE) ,'TZH:TZM') nodst
from dual;
As you are getting different results in SQL Developer and SQL*Plus, you seem to have different session time zones in those two clients. You can check by querying sessiontimezone in each. SQL Developer sets the session time zone from the Java time zone (picked up from the operating system by default; you can override that by passing a user.timezone value at start-up). SQL*Plus uses the ORA_SDTZ environment variable, so you can set that to match your locale if you don't want to set it from within the database with alter session (manually or via login.sql); and if unset it defaults to 'OS_TZ':
The default value of the ORA_SDTZ variable, which is used when the variable is not set or it is set to an invalid value, is 'OS_TZ'.
... and it's picking that up as an offset (-04:00) rather than a region.
If you always want the result to be in a particular time zone regardless of any user's session settings, then you can state which one to use instead, e.g.:
select to_char(FROM_TZ(CAST (sysdate AS TIMESTAMP), 'America/New_York') ,'TZH:TZM') dst,
to_char(FROM_TZ(CAST(sysdate-160 AS TIMESTAMP), 'America/New_York') ,'TZH:TZM') nodst
from dual;
db<>fiddle with several session settings to demonstrate.
Presumably your real query is working from a variable date value, not sysdate; otherwise you could use systimestamp instead, with at time zone to adjust to a different zone if necessary.

This gives the correct dst-adjusted timezone offset (eastern) with one date in dst, and the other not.
No, it gives you a manually adjusted value that appears to be correct; however, when DST ends then your query will be incorrect and it will require adjusting ... then next spring it will require adjusting again ... and next autumn.
If you want the correct values then let Oracle adjust the time zones (and you don't need to cast SYSDATE to a TIMESTAMP WITH TIME ZONE, you can just use SYSTIMESTAMP or CURRENT_TIMESTAMP):
SELECT TO_CHAR(SYSTIMESTAMP AT TIME ZONE 'US/Eastern', 'TZH:TZM')
AS timezone
FROM DUAL

Related

Oracle PL/SQL How to get time in Paris?

What is the best way to always get the right time in Europe/Paris (including summer/winter times) ?
So far, I'm using the following query :
select FROM_TZ(CAST(Sysdate AS TIMESTAMP), 'Europe/Paris') from dual
It was working nicely in a previous server. However, we have changed our database server and now we are getting a difference of one hour.
Is there any way to get always the correct time in Paris ?
Thanks.
SYSDATE is returned in the time zone of database server's operating system. When you run FROM_TZ(CAST(Sysdate AS TIMESTAMP), 'Europe/Paris') then you "attach" time zone Europe/Paris to SYSDATE.
So, FROM_TZ(CAST(Sysdate AS TIMESTAMP), 'Europe/Paris') is only correct if the time zone of database server's operating system is Europe/Paris.
Try SYSTIMESTAMP AT TIME ZONE 'Europe/Paris' then result is always correct because SYSTIMESTAMP returns a TIMESTAMP WITH TIME ZONE value and time zones are properly converted.

Different timestamps for same sql query in Source Oracle Database and Target same Oracle Database while using Informatica

The source is having Createddate as 17-JAN-18 17.22.39.000000000 in my table.
When I execute the following query:
select CAST(Createddate AT TIME ZONE 'UTC' AS Timestamp) from Employee
on Oracle Database, It is giving below results.
17-JAN-18 15.22.39.000000000
But when I use the same SQL Query in Source Qualifier(Informatica) the target is getting below result which is in the same Oracle Database.
17-JAN-18 12.22.39.000000000
I am getting a 1 hour difference. Can someone help how can I get the same timestamp?
I assume your Createddate value is a TIMESTAMP value (without TIME ZONE).
When you run CAST(Createddate AT TIME ZONE 'UTC' AS Timestamp) then Oracle actually does
CAST(
FROM_TZ(Createddate, SESSIONTIMEZONE)
AT TIME ZONE 'UTC' AS Timestamp)
I.e. it appends the current session time zone to the timestamp value and then it is converted to new time zone.
So, the session time zones are different. The most reliable solution would be to set the time zone explicitly, e. g.
CAST(FROM_TZ(Createddate, 'Europe/Zurich') AT TIME ZONE 'UTC' AS Timestamp)
btw, for your function there is a shortcut, simply use like
SYS_EXTRACT_UTC(FROM_TZ(Createddate, 'Europe/Zurich'))

Oracle server timezone using SQL query

I ran
select SYSDATE from dual;
Output:
SYSDATE |
-------------------|
2019-10-09 08:55:29|
Then I ran,
SELECT DBTIMEZONE FROM DUAL;
Output:
DBTIMEZONE|
----------|
+00:00 |
In the first output, time is in EST and 2nd output suggests timezone is UTC.
How do I check oracle server timezone via SQL query?
From the docs:
The database time zone [DBTIMEZONE] is relevant only for TIMESTAMP WITH LOCAL TIME ZONE columns. Oracle recommends that you set the database time zone to UTC (0:00)...
SYSDATE/SYSTIMESTAMP will return the time in the database server's OS timezone. Selecting a TIMESTAMP WITH LOCAL TIME ZONE datatype will return the time in your session's timezone (ie, SESSIONTIMEZONE).
select
CAST(systimestamp AS timestamp(0) with local time zone) as local_time,
systimestamp as server_time
from dual;
DBTIMEZONE is only used as the base timezone stored in TIMESTAMP WITH LOCAL TIME ZONE columns - which you never see, because when you select from one of those columns it gets translated into your session timezone.
See this similar question for a very detailed answer.
It is a common misunderstanding that SYSDATE or SYSTIMESTAMP are returned at DBTIMEZONE
SYSDATE and SYSTIMESTAMP are given in the time zone of database server's operating system. If you like to interrogate the time zone of database server's operating system run
SELECT TO_CHAR(SYSTIMESTAMP, 'tzr') FROM dual;
see also How to handle Day Light Saving in Oracle database

Trying to retrieve the UTC time-stamp in Oracle, does using "from_tz" cause an issue?

Will using the following query to retrieve the UTC timestamp from an oracle database cause an issue? I do not want to alter the database timezone parameter in order to retrieve the correct date. I do not want to do alter database set time_zone.
My query at the moment is:
select from_tz(CAST (sys_extract_utc(systimestamp) AS TIMESTAMP), '+00:00') from dual;
I would like to know if this query will result in the correct UTC date in all circumstances regardless of the EST/EDT status.
I don't see anything wrong with your query. Note that if you want to work in UTC for your session, you could simply:
ALTER SESSION SET TIME_ZONE = '0:00';
select CURRENT_TIMESTAMP from dual;
output
11/1/2016 5:48:55.115282 PM +00:00
That would change your current_timestamp (and localtimestamp) for your entire session.
Your query is just setting timezone but not converting time. If that's what you were looking for it is ok. Is local time is 3AM you will return 3AM UTC.
I think you're looking for that query:
select cast(sysdate as timestamp) at time zone 'UTC' from dual;
And the apply
select from_tz(cast(systimestamp at time zone 'UTC' as timestamp), '+0:00') from dual;
Some general notes:
SYSTIMESTAMP and SYSDATE are given in time zone of your database server's operating system. Thus changing database time zone (i.e. DBTIMEZONE) does not change anything.
CAST (sys_extract_utc(systimestamp) AS TIMESTAMP), resp. cast(systimestamp at time zone 'UTC' as timestamp) have a problem. You convert your timestamp to UTC but by CAST(... AS TIMESTAMP) you remove any time zone information from that value. If you like to do any further conversion (e.g. again to TIMESTAMP WITH TIME ZONE value) then your input UTC value is considered to be a SESSIONTIMEZONE value.
from_tz(CAST (sys_extract_utc(systimestamp) AS TIMESTAMP), '+00:00') does following:
Get current time in time zone of your database server's operating system, include time zone information.
Convert this time to UTC, cut time zone information
Append time zone information (+00:00) to this value
Correct output but redundant conversion
cast(sysdate as timestamp) at time zone 'UTC' does following:
Get current time in time zone of your database server's operating system, without any time zone information.
Cast to TIMESTAMP (basically no effect at all)
Consider this value as time in your local session time zone (SESSIONTIMEZONE) and convert to UTC.
Correct output only if time zone of your database server's operating system is the same as your local session time zone, otherwise you get wrong result.
from_tz(cast(systimestamp at time zone 'UTC' as timestamp), '+0:00') does following:
Get current time in time zone of your database server's operating system, include time zone information.
Convert this time to UTC
Cut time zone information
Append time zone information (+00:00) to this value
Correct output but redundant conversion
from_tz(cast(systimestamp as timestamp), '+0:00') does following:
Get current time in time zone of your database server's operating system, include time zone information.
Cut time zone information
Append time zone information (+00:00) to this value
Correct output only if time zone of your database server's operating system is UTC.

How to get UTC value for SYSDATE on Oracle

Probably a classic... Would you know a easy trick to retrieve an UTC value of SYSDATE on Oracle (best would be getting something working on the 8th version as well).
For now I've custom function :(
Cheers,
Stefan
You can use
SELECT SYS_EXTRACT_UTC(TIMESTAMP '2000-03-28 11:30:00.00 -02:00') FROM DUAL;
You may also need to change your timezone
ALTER SESSION SET TIME_ZONE = 'Europe/Berlin';
Or read it
SELECT SESSIONTIMEZONE, CURRENT_TIMESTAMP FROM dual;
select sys_extract_utc(systimestamp) from dual;
Won't work on Oracle 8, though.
Usually, I work with DATE columns, not the larger but more precise TIMESTAMP used by some answers.
The following will return the current UTC date as just that -- a DATE.
CAST(sys_extract_utc(SYSTIMESTAMP) AS DATE)
I often store dates like this, usually with the field name ending in _UTC to make it clear for the developer. This allows me to avoid the complexity of time zones until last-minute conversion by the user's client. Oracle can store time zone detail with some data types, but those types require more table space than DATE, and knowledge of the original time zone is not always required.
I'm using:
SELECT CAST(SYSTIMESTAMP AT TIME ZONE 'UTC' AS DATE) FROM DUAL;
It's working fine for me.
If you want a timestamp instead of just a date with sysdate, you can specify a timezone using systimestamp:
select systimestamp at time zone 'UTC' from dual
outputs: 29-AUG-17 06.51.14.781998000 PM UTC

Resources