In below, why isn't Daylight savings included in to_char()? How can i get the time with daylight savings?
SELECT systimestamp AT TIME ZONE 'Australia/Adelaide' from dual;
SELECT TO_CHAR(systimestamp AT TIME ZONE 'Australia/Adelaide' ,'yyyy-MM-dd HH:MI:SS AM') from dual;
returns
16-OCT-13 07.19.01.165681000 PM AUSTRALIA/ADELAIDE
2013-10-16 06:19:01 PM
select to_char( systimestamp at time zone 'AUSTRALIA/ADELAIDE',
'HH24:MI:SS TZR TZD' ) from dual
http://docs.oracle.com/cd/B19306_01/server.102/b14200/sql_elements004.htm#i34510
The issue was because of outdated timezones files in oracle server. Adelaide timezones were updated around 2008 or 2007. once timezone files were updated issue got resolved.
Related
I have a problem with the time that Oracle gives me when working with applications.
I currently connect from an application server (apx1) to a server containing Oracle 19c (bdx1) for database operations.
Both the application server and the database server are in the Canary Islands, so it must show/work local time there (GMT +1 in summer, GMT in winter).
If I launch the date command on the servers, the time appears correct.
[oracle#apx1 oracle]$ date
vie jul 1 14:25:49 BST 2022
[oracle#bdx1 ~]$ date
vie jul 1 14:25:46 BST 2022
However, after making the connection from apx1 to bdx1, I get this time offset:
SQL> select systimestamp, current_timestamp, localtimestamp from dual;
SYSTIMESTAMP
---------------------------------------------------------------------------
CURRENT_TIMESTAMP
---------------------------------------------------------------------------
LOCALTIMESTAMP
---------------------------------------------------------------------------
01/07/22 15:27:39,762772 +02:00
01/07/22 14:27:39,762775 +01:00
01/07/22 14:27:39,762775
The SESSIONTIMEZONE parameter returns the correct value, +1:
SQL> SELECT SESSIONTIMEZONE FROM DUAL;
SESSIONTIMEZONE
---------------------------------------------------------------------------
+01:00
However, if I run this query (from the application server to the database):
sac#apx1> sqlplus user/pass#bdx1
SQL> select to_char(sysdate, 'dd mm yyyy hh24:mi:ss') "SYSDATE", to_char(current_date, 'dd mm yyyy hh24:mi:ss') "CURRENT_DATE" from dual;
SYSDATE CURRENT_DATE
------------------- -------------------
01 07 2022 16:26:23 01 07 2022 15:26:23
SYSDATE result is incorrect with respect to the time that should appear.
What do you mean by "configure to correct this offset"?
LOCALTIMESTAMP returns the current date and time in the session time zone in a value of datatype TIMESTAMP.
CURRENT_TIMESTAMP returns the current date and time in the session time zone in a value of datatype TIMESTAMP WITH TIME ZONE.
SYSTIMESTAMP returns the current date and time in the time zone of database server's operating system in a value of datatype TIMESTAMP WITH TIME ZONE.
Set the SESSIONTIMEZONE and/or database server time zone properly.
The solution was posted on DBA stackexchange: https://dba.stackexchange.com/a/314026/175060.
You have to set the parameter at cluster level:
srvctl setenv database -db DBNAME -env "TZ=Atlantic/Canary".
And then restart the DB hosts, since a CRS restart is not enough.
I have a query like this:
SELECT
to_date(to_char((from_tz(to_timestamp(to_char(my_column, 'YYYY-MM-DD HH:MI:SS PM'), 'YYYY-MM-DD HH:MI:SS PM') ,'America/Edmonton')at time zone 'America/Vancouver'),'YYYY-MM-DD'),'YYYY-MM-DD') as Date_Column
FROM
my_table
It converts the time between MST to PST. This works most of the time except when daylight savings time occurs. Then a situation happens when in the clock moves forward an hour, and then since an hour is lost (for example 1:59 to the 3:00 am) then we are trying to convert a fictional time.
So I am aware of the issue, and I know Oracle will throw this error for that reason:
ORA-01878: specified field not found in datetime or interval
I've looked all over the Internet for a possible work around but can't really find anything that works. I just want to modify my query so that it can tell what time of year it is and either do the conversation when the time exists, or handle the time somehow when it does not exists. Perhaps add the extra hour when it's missing, and remove it when it's the other time of year.
Does anyone have a solution for this? Is this an impossible problem?
Instead of all the conversions you are using, just use AT TIME ZONE. You may need to take extra care depending on the data type of your column. The AT TIME ZONE functionality will always take into account daylights savings time.
If your column is a TIMESTAMP WITH TIME ZONE, that would be ideal
because you could just say AT TIME ZONE 'PST' and you would get the
time in PST.
If the column is the datatype TIMESTAMP, when you use AT TIME ZONE it
will convert from the time zone of the current session to whatever
you specify.
If your column is a DATE, you will need to convert it to a TIMESTAMP first, then you can use the AT TIME ZONE function. Converting the DATE to TIMESTAMP will make the time zone 0:00 offset so be sure to account for that.
Another handy trick is to use AT LOCAL. This will convert the timestamp to the time zone of the current session. This may be handy if you have users of your application that are in multiple time zones.
Example
I am in the time zone -04:00 (East coast US) which is why that appears as my time zone in the examples below.
WITH
my_table
AS
(SELECT TIMESTAMP '2021-01-01 8:00:00 -7:00' AS ts_with_tz,
TIMESTAMP '2021-01-01 8:00:00' AS ts,
DATE '2021-01-01' + (8 / 24) AS dt
FROM DUAL)
SELECT 1 AS example_num,
t.ts_with_tz,
t.ts,
t.dt
FROM my_table t
UNION ALL
SELECT 2 AS example_num,
t.ts_with_tz AT TIME ZONE 'PST',
t.ts AT TIME ZONE 'PST',
TO_TIMESTAMP (t.dt) AT TIME ZONE 'PST'
FROM my_table t
ORDER BY 1;
RESULT
EXAMPLE_NUM TS_WITH_TZ TS DT
______________ ______________________________________________________ ______________________________________________________ ______________________________________________________
1 01-JAN-21 08.00.00.000000000 AM -07:00 01-JAN-21 08.00.00.000000000 AM AMERICA/NEW_YORK 01-JAN-21 08.00.00.000000000 AM AMERICA/NEW_YORK
2 01-JAN-21 07.00.00.000000000 AM AMERICA/LOS_ANGELES 01-JAN-21 05.00.00.000000000 AM AMERICA/LOS_ANGELES 31-DEC-20 09.00.00.000000000 PM AMERICA/LOS_ANGELES
I need to compare database generated dates (column values defaulting to SYSDATE) to hand written time stamps recorded with the time zone. This is the comparison I am trying:
where trunc(updated, 'mi') >= to_timestamp_tz('2017-10-24 04:45 US/Pacific', 'YYYY-MM-DD HH24:mi TZR')
I assume that a character string converted to a TIMESTAMP WITH TIME ZONE should be comparable to a DATE. However, this only works if the database is located in my own time zone. Otherwise, I have to manually convert the external time stamp to the database time zone. For example, if I am in BST and the database is in EST, I have to write:
where trunc(updated, 'mi') >= to_timestamp_tz('2017-10-24 04:45 US/Pacific', 'YYYY-MM-DD HH24:mi TZR')
Where 04:45 = 10:45 - 6, and 6 is the difference between BST and EST. This looks absolutely counter-intuitive as the original time stamp has been recorded in PST and is therefore entered as US/Pacific. Could anybody please explain why this conversion is needed? I would also appreciate if somebody suggests a better solution.
You can cast your DATE column to a TIMESTAMP WITH TIME ZONE value like this:
WHERE
FROM_TZ(CAST(TRUNC(updated, 'mi') AS TIMESTAMP),
(SELECT TO_CHAR(SYSTIMESTAMP, 'TZR') FROM dual)) >= to_timestamp_tz('2017-10-24 04:45 US/Pacific', 'YYYY-MM-DD HH24:mi TZR')
but it works also the other way around, i.e. convert TIMESTAMP WITH TIME ZONE to DATE in database time zone:
WHERE
TRUNC(updated, 'mi') >=
CAST(TO_TIMESTAMP_TZ('2017-10-24 04:45 US/Pacific', 'YYYY-MM-DD HH24:mi TZR') AT TIME ZONE (SELECT TO_CHAR(SYSTIMESTAMP, 'TZR') FROM dual) AS DATE)
SYDATE is provided in the time zone of database server's operating system (NOT DBTIMEZONE) , thus you have to use (SELECT TO_CHAR(SYSTIMESTAMP, 'TZR') FROM dual) or provide hard-coded value if appropriate.
This approach fails if any users inserted/updated any updated using his current local time zone. In such cases the time zone information is lost and there is no way to recover it.
If you are running this query in any of oracle clients, You can also change the session setting by running
ALTER SESSION SET TIME_ZONE ='BST';
When you change the session time_zone all the date values coming from database column and time stamp values passed without time zone will be converted to BST.
hence it will ensure that the comparison is happening in common time zone
Below query is used in my code to get the timezone from database. (DB is in central time zone)
SELECT DBTIMEZONE FROM DUAL;
-05:00
When daylight saving is on (CDT), its expected result.
but when daylight saving ends (CST), my result should be GMT-06, but i am still getting GMT-05.
Googled and got below options :
SELECT TO_CHAR(SYSTIMESTAMP, 'TZR') FROM dual;
SELECT TZ_OFFSET('CST6CDT') FROM DUAL;
Will above queries run correctly accordingly to CST and CDT ??
DBTIMEZONE does not determine the time zone of SYSTIMESTAMP (or SYSDATE)
Time zone of SYSTIMESTAMP is the time zone of database server's operating system.
DBTIMEZONE is only relevant for data type TIMESTAMP WITH LOCAL TIME ZONE and defines the time zone in which those values are stored internaly. You cannot change DBTIMEZONE on your database if the database contains a table with a TIMESTAMP WITH LOCAL TIME ZONE column and the column contains data.
SELECT TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI')
,TO_CHAR(CURRENT_DATE, 'YYYY-MM-DD HH24:MI')
,TO_CHAR(SYSTIMESTAMP, 'YYYY-MM-DD HH24:MI TZR')
,TO_CHAR(CURRENT_TIMESTAMP, 'YYYY-MM-DD HH24:MI TZR')
,TO_CHAR(LOCALTIMESTAMP, 'YYYY-MM-DD HH24:MI TZR')
,DBTIMEZONE
,SESSIONTIMEZONE
FROM DUAL;
Is returning:
2012-01-16 11:42
2012-01-16 11:42
2012-01-16 11:42 -06:00
2012-01-16 11:42 -06:00
2012-01-16 11:42 +00:00
+00:00
-06:00
It seems to think the database time zone is GMT, yet the SYSDATE is the same as the CURRENT_DATE.
When I remote into that server (Windows), the time zone is apparently CST (however, I am aware that this could be picking up my Terminal Services Client Time Zone Offset, but this machine doesn't have Terminal Services on it, just administrative)
Running the same thing against a server in Amsterdam (4 minutes later all from the same TOAD client), I'm getting:
2012-01-16 18:46
2012-01-16 11:46
2012-01-16 18:46 +01:00
2012-01-16 11:46 -06:00
2012-01-16 11:46 +00:00
+02:00
-06:00
Note the +2, but at least the SYSDATE and CURRENT_DATE are differing.
What is going on here? Where does SYSDATE come from and is there anything else which affects it?
It seems like DBTIMEZONE is not used for any of these things? So what is DBTIMEZONE used for?
There are actually 3 timezones here, not 2
the timezone of the session/client
Shown in SESSIONTIMEZONE
This is the timezone of CURRENT_DATE, LOCALTIMESTAMP and CURRENT_TIMESTAMP. The difference between those 3 is the return type, they return a DATE, TIMESTAMP, and TIMESTAMP WITH TIME ZONE respectively)
The database timezone
Shown in DBTIMEZONE
This is the the timezone used for the internal storage of TIMESTAMP WITH LOCAL TIME ZONE values. Note that values are converted to/from session timezone on insert/select so it actually isn't as important as it seems
This is NOT the timezone of SYSDATE/SYSTIMESTAMP
The database OS timezone
In unix, it is based on the TZ variable when Oracle is started
This is the timezone of SYSDATE and SYSTIMESTAMP
In your first example, I can see that the session TZ is UTC-6, the database TZ is UTC, and the database OS timezone is UTC-6.
In your second example, I can see that the session TZ is UTC-6, the database TZ is UTC+2, and the database OS timezone is UTC+1.
The details are in the fine print of the documentation. Take a look at the Return Type, and the actual Timezone the DATE or TIMESTAMP is calculated in.
SYSDATE
Return Type: DATE
Time Zone: Host OS of Database Server
CURRENT_DATE
Return Type: DATE
Time Zone: Session
SYSTIMESTAMP
Return Type: TIMESTAMP WITH TIME ZONE
Time Zone: Host OS of Database Server
CURRENT_SYSTIMESTAMP
Return Type: TIMESTAMP WITH TIME ZONE
Time Zone: Session
LOCALTIMESTAMP
Return Type: TIMESTAMP
Time Zone: Session
DBTIMEZONE
Time Zone: DB Time Zone. Inherits from DB Server OS, but can be overridden using set at DB Creation or Alter using TIME_ZONE DB Parameter (SET TIME_ZONE=...). This affects the time zone used for TIMESTAMP WITH LOCAL TIME ZONE datataypes.
SESSIONTIMEZONE
Time Zone: Session Timezone. Inherits from Session hosting OS, but can be overridden using ALTER SESSION (ALTER SESSION SET TIME_ZONE=...).
Return Type, indicates whether or not the Timezone is available within the Datatype. If you try to print TZR if datatype does not carry TimeZone, then it will just show up as +00:00 (doesn't mean it is GMT). Otherwise It will show the TimeZone matching either the Database or Session as indicated.
Time Zone, indicates in which Timezone the time is calculated. For matching TimeZone, the same Date/Time will be shown (HH24:MI).
Note that none of the FUNCTIONS return TIME in the Time Zone set with the DB TIME_ZONE (or as returned by the DBTIMEZONE function). That is, none of the functions also return a datatype of TIMESTAMP WITH LOCAL TIME ZONE. Howver you can convert the output of any of the functions that does return a timezone into a different timezone (including DBTIMEZONE) as follows:
SELECT SYSTIMESTAMP AT TIME ZONE DBTIMEZONE FROM DUAL;
More information on my blog.
Use UTC time and offset your timezone from UTC, To get UTC in Oracle use SYS_EXTRACT_UTC
Convert SYSTEMDATE to UTC
select sys_extract_utc(systimestamp) from dual;
As for the difference the definition from Oracle documentation might help to explain:
LOCALTIMESTAMP returns the current date and time in the session time zone in a value of datatype TIMESTAMP
CURRENT_TIMESTAMP returns the current date and time in the session time zone, in a value of datatype TIMESTAMP WITH TIME ZONE
SYSTIMESTAMP returns the system date, including fractional seconds and time zone, of the system on which the database resides
CURRENT_DATE returns the current date in the session time zone, in a value in the Gregorian calendar of datatype DATE.
SYSDATE returns the current date and time set for the operating system on which the database resides.
DBTIMEZONE returns the value of the database time zone.