"TIMESTAMP WITH TIME ZONE" <--> DateTImeOffset mapping won't deliver the Zone part on INSERT commands (Entity Framework + Oracle) - oracle

I use EF (EDMX model - DB first) to map "TIMESTAMP WITH TIME ZONE" to a DateTimeOffset. when I commit the DateTimeOffset to Oracle, the Zone part is saved incorrectly.
So if using the model, for example, to insert the value 29/02/2012 10:10:10 +04:00, the value that is actually stored in Oracle is 29/02/2012 10:10:10 +02:00 (assuming +02:00 is local zone)
Note that the mappings works just fine when querying the data. Only INSERT (via ObjectContext.SaveChanges()) is broken...
I've debugged into the "Oracle.DataAccess.dll" ( using ILSpy :) ) and found that the mapping code for EF omits the zone (the "Oracle Data Provider" passes the DateTimeOffset.DateTime only).
Does anyone know a workaround?
Thanks in advance
Eli
BTW: I am using .net4, EF4, Oracle 11g, ODAC 11.2 Release 4 (11.2.0.3.0)

You could try to dynamicly set the Session Time Zone, which "takes effect when a TIMESTAMP value is converted to the TIMESTAMP WITH
TIME ZONE or TIMESTAMP WITH LOCAL TIME ZONE datatype".
...a terrible hack of course, also because you cannot execute alter session directly through SQL. You'd have to use something like
begin DBMS_UTITLITY.EXEC_DDL_STATEMENT ('Alter Session Set TIME_ZONE = ''+04:00'''); end;

Oracle admitted this was a bug https://community.oracle.com/thread/2360615?tstart=0. And they sad it had been fixed in bug 13851978. But my test on oracle client on 11.2.0.3.0 is still failed.
On solution is as #HAL 9000 suggested setting the session's time zone with the hours and minutes in time span of DatetimeOffset before saving to database. But this won't work if there are multiple DatetimeOffset properties in one object and these properties have different timespans inside Datetimeoffset.
Another alternative is replacing ODP.NET with 3rd-party data provider such as Devart's DotConnect(I've tested this, it works for me). There is a comparison in stackoverflow about different data providers https://stackoverflow.com/a/8298684/1443505.

Storing offsets in the database might not hold good for Daylight savings offset Management.
It will be a good practice to always use timezone names over offset values where the purpose is unaffected.
--To store actual time and timezone value
to_timestamp_tz('10-SEP-2014 01:40:00.000000000 US/Pacific','DD-MON-YYYY HH24:MI:SS.FF9 TZR')
--To store actual time at timezone converted to UTC timezone value for uniformity
to_timestamp_tz('10-SEP-2014 01:40:00.000000000 US/Pacific','DD-MON-YYYY HH24:MI:SS.FF9 TZR') at time zone 'UTC'

Related

Oracle DBTIMEZONE [duplicate]

In one of the Oracle database server it is showing "+01:00" when I fire the "Select dbtimezone from dual" does that mean in summer the clock will shift one hour ahead ?. In another server it is showing "+00:00" does that mean the database server setting is GMT ? but I am using the sysdate in oracle pl/sql. Client is saying the Aix server is on DST so would that mean the DB server will adopt the AIX server setting after clock change ?
How to fix this problem.
Answer is: It depends.
In total your database has three time zones
1. Your session time zone: SESSIONTIMEZONE
This you can change by ALTER SESSION SET TIME_ZONE=... at any time. It is relevant for result of
CURRENT_DATE
LOCALTIMESTAMP
CURRENT_TIMESTAMP
It is also the target time zone when you do CAST({TIMESTAMP/DATE without any timezone} AS TIMESTAMP WITH {LOCAL} TIME ZONE)
Default SESSIONTIMEZONE can be set by environment variable ORA_SDTZ or (on Windows) by registry entry HKLM\SOFTWARE\Wow6432Node\ORACLE\KEY_%ORACLE_HOME_NAME%\ORA_SDTZ (for 32 bit Client), resp. HKLM\SOFTWARE\ORACLE\KEY_%ORACLE_HOME_NAME%\ORA_SDTZ (for 64 bit Client).
2. The database time zone: DBTIMEZONE
Actually this is not so important in daily use, it is relevant only for TIMESTAMP WITH LOCAL TIME ZONE data type columns and defines the storage format.
This is NOT the timezone of SYSDATE or SYSTIMESTAMP!!!
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. Otherwise it can be changed with ALTER DATABASE SET TIME_ZONE='...';. The change does not take effect until the database has been shut down and restarted.
DBTIMEZONE is set when database is created. If no time zone is provided while database creation then Oracle defaults to the time zone of the server's operating system.
3. The time zone of database server's operating system:
This time zone is relevant for result of
SYSDATE
SYSTIMESTAMP
Naturally this time zone cannot be changed on database level. In case your home country uses Daylight Saving Times, this time zone may change twice a year. You can interrogate it with SELECT TO_CHAR(SYSTIMESTAMP, 'tzr') FROM dual;, for instance.
So, if your DB Server OS is setup properly, then you should get summer times from next week on (at least for Europe)
In one of the Oracle database server it is showing "+01:00" when I fire the "Select dbtimezone from dual" does that mean in summer the clock will shift one hour ahead ?
It means your database timezone is +01:00 compared to UTC time zone.
From docs,
DBTIMEZONE returns the value of the database time zone. The return
type is a time zone offset (a character type in the format
'[+|-]TZH:TZM') or a time zone region name, depending on how the user
specified the database time zone value in the most recent CREATE
DATABASE or ALTER DATABASE statement.
So, database's DBTIMEZONE inherits the timezone value from DB Server OS.
While SESSIONTIMEZONE could be overridden at session level by an alter session statement.
For example,
ALTER SESSION SET TIME_ZONE=<timezone>;
This modifies the time zone of the TIMESTAMP WITH LOCAL TIME ZONE.
In another server it is showing "+00:00" does that mean the database server setting is GMT ?
+00:00 can be assumed that the database time zone is set to UTC time zone.
For example,
SELECT DBTIMEZONE FROM DUAL;
DBTIME
------
+00:00
Read more from documentation.
I resolved this issue by using the below command
"Select Systimestamp at time zone 'GMT' from DUAL' This command wil always give the GMT date and time irrespective of OS time.
Oracle Database automatically determines whether Daylight Saving Time is in effect for a specified time zone and returns the corresponding local time. Normally, date/time values are sufficient to allow Oracle Database to determine whether Daylight Saving Time is in effect for a specified time zone. The periods when Daylight Saving Time begins or ends are boundary cases. For example, in the Eastern region of the United States, the time changes from 01:59:59 a.m. to 3:00:00 a.m. when Daylight Saving Time goes into effect. The interval between 02:00:00 and 02:59:59 a.m. does not exist. Values in that interval are invalid. When Daylight Saving Time ends, the time changes from 02:00:00 a.m. to 01:00:01 a.m.
Further explaination can be found here.
http://docs.oracle.com/cd/E18283_01/server.112/e10729/ch4datetime.htm#insertedID11

Timestamp variations between oracle and postgres

Currently, I am working on migrating an Oracle database schema to Postgres. As part of it I have to convert a custom utility function in Oracle which generates timestamps based on timezone. But the values obtained from Oracle and Postgres seem to vary by one hour.
Oracle:
SELECT (to_timestamp_tz('20300714 235959 CET','YYYYMMDD HH24MISS TZR') - to_timestamp_tz('19700101 000000 GMT','YYYYMMDD HH24MISS TZR'))
as foo FROM dual;
yields +22109 21:59:59.000000
Postgres:
select ('20300714 235959'::timestamp AT TIME ZONE 'CET') - ('19700101 000000'::timestamp AT TIME ZONE 'GMT') as foo;
yields 22109 days 22:59:59
I guess the reason for this difference is because of daylight saving but I am not sure. Can anyone help me out with this problem.
I am using Postgres v9.6 and Oracle 12c.
Well, I found the mistake I was doing. Postgres seems to handle the abbreviated timezone name and full timezone name differently. In case if you want to incorporate daylight related changes you would have to use full timezone name. In my case using 'Europe/Amsterdam' instead of 'CET' yielded the same result as that of Oracle.
To find the complete list of full timezone names supported by Postgres, I used the query:
select * from pg_timezone_names where abbrev='CET';

How to handle Day Light Saving in Oracle database

In one of the Oracle database server it is showing "+01:00" when I fire the "Select dbtimezone from dual" does that mean in summer the clock will shift one hour ahead ?. In another server it is showing "+00:00" does that mean the database server setting is GMT ? but I am using the sysdate in oracle pl/sql. Client is saying the Aix server is on DST so would that mean the DB server will adopt the AIX server setting after clock change ?
How to fix this problem.
Answer is: It depends.
In total your database has three time zones
1. Your session time zone: SESSIONTIMEZONE
This you can change by ALTER SESSION SET TIME_ZONE=... at any time. It is relevant for result of
CURRENT_DATE
LOCALTIMESTAMP
CURRENT_TIMESTAMP
It is also the target time zone when you do CAST({TIMESTAMP/DATE without any timezone} AS TIMESTAMP WITH {LOCAL} TIME ZONE)
Default SESSIONTIMEZONE can be set by environment variable ORA_SDTZ or (on Windows) by registry entry HKLM\SOFTWARE\Wow6432Node\ORACLE\KEY_%ORACLE_HOME_NAME%\ORA_SDTZ (for 32 bit Client), resp. HKLM\SOFTWARE\ORACLE\KEY_%ORACLE_HOME_NAME%\ORA_SDTZ (for 64 bit Client).
2. The database time zone: DBTIMEZONE
Actually this is not so important in daily use, it is relevant only for TIMESTAMP WITH LOCAL TIME ZONE data type columns and defines the storage format.
This is NOT the timezone of SYSDATE or SYSTIMESTAMP!!!
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. Otherwise it can be changed with ALTER DATABASE SET TIME_ZONE='...';. The change does not take effect until the database has been shut down and restarted.
DBTIMEZONE is set when database is created. If no time zone is provided while database creation then Oracle defaults to the time zone of the server's operating system.
3. The time zone of database server's operating system:
This time zone is relevant for result of
SYSDATE
SYSTIMESTAMP
Naturally this time zone cannot be changed on database level. In case your home country uses Daylight Saving Times, this time zone may change twice a year. You can interrogate it with SELECT TO_CHAR(SYSTIMESTAMP, 'tzr') FROM dual;, for instance.
So, if your DB Server OS is setup properly, then you should get summer times from next week on (at least for Europe)
In one of the Oracle database server it is showing "+01:00" when I fire the "Select dbtimezone from dual" does that mean in summer the clock will shift one hour ahead ?
It means your database timezone is +01:00 compared to UTC time zone.
From docs,
DBTIMEZONE returns the value of the database time zone. The return
type is a time zone offset (a character type in the format
'[+|-]TZH:TZM') or a time zone region name, depending on how the user
specified the database time zone value in the most recent CREATE
DATABASE or ALTER DATABASE statement.
So, database's DBTIMEZONE inherits the timezone value from DB Server OS.
While SESSIONTIMEZONE could be overridden at session level by an alter session statement.
For example,
ALTER SESSION SET TIME_ZONE=<timezone>;
This modifies the time zone of the TIMESTAMP WITH LOCAL TIME ZONE.
In another server it is showing "+00:00" does that mean the database server setting is GMT ?
+00:00 can be assumed that the database time zone is set to UTC time zone.
For example,
SELECT DBTIMEZONE FROM DUAL;
DBTIME
------
+00:00
Read more from documentation.
I resolved this issue by using the below command
"Select Systimestamp at time zone 'GMT' from DUAL' This command wil always give the GMT date and time irrespective of OS time.
Oracle Database automatically determines whether Daylight Saving Time is in effect for a specified time zone and returns the corresponding local time. Normally, date/time values are sufficient to allow Oracle Database to determine whether Daylight Saving Time is in effect for a specified time zone. The periods when Daylight Saving Time begins or ends are boundary cases. For example, in the Eastern region of the United States, the time changes from 01:59:59 a.m. to 3:00:00 a.m. when Daylight Saving Time goes into effect. The interval between 02:00:00 and 02:59:59 a.m. does not exist. Values in that interval are invalid. When Daylight Saving Time ends, the time changes from 02:00:00 a.m. to 01:00:01 a.m.
Further explaination can be found here.
http://docs.oracle.com/cd/E18283_01/server.112/e10729/ch4datetime.htm#insertedID11

Why does CURRENT_DATE contains time in Oracle Mode?

When I connect to
jdbc:hsqldb:mem:lbw;sql.syntax_ora=true
the statement
SELECT CURRENT_DATE FROM dual
results in
2014-01-31 10:35:54
This is in opposite to connections without Oracle syntax mode, where CURRENT_DATE doesn't contain time.
As described in the HSQLDB documentation, DATE is interpreted as TIMESTAMP(0) in Oracle syntax mode. But in Oracle 10g itself, CURRENT_DATE behaves as expected (without time).
This difference seems to include DATE fields in general.
Why does HSQLDB behave this way?
Is there a way to disable the automatic conversion?
From the same HSQLDB documentation you linked to:
Datetime types
HSQLDB fully supports datetime and interval types and operations,
including all relevant optional features, as specified by the SQL
Standard since SQL-92. The two groups of types are complementary.
The DATE type represents a calendar date with YEAR, MONTH and DAY
fields.
The TIME type represents time of day with HOUR, MINUTE and SECOND
fields, plus an optional SECOND FRACTION field.
The TIMESTAMP type represents the combination of DATE and TIME types.
The Oracle compatibility section says:
The DATE type is interpreted as TIMESTAMP(0) in ORA syntax mode.
Oracle's DATE data type "contains the datetime fields YEAR, MONTH, DAY, HOUR, MINUTE, and SECOND". So it's equivalent to an HSQLDB TIMESTAMP(0) data type, and in Oracle mode it is treated as such.
Oracle dates always have a time component, even if it is all zeros for midnight. If your SQL client doesn't show it by default you can see that with select to_char(current_date, 'YYYY-MM-DD HH24:MI:SS'), as others have already pointed out.
In normal non-Oracle mode HSQLDB is just treating the value as an SQL-standard DATE and dropping the time portion; in Oracle mode it preserves the time. There doesn't seem to be any way to selectively enable some aspects of the Oracle mode, so you're stuck with the time - really not sure why that is an issue though since it's just reflecting the data you have in your database. If you want to ignore the time you could always select trunc(current_date), which will take the time back to midnight; but it will still show as 2014-01-31 00:00:00 because it's still going to be treated as TIMESTAMP(0).

Oracle change dbtimezone

My database was configured with an dbtimezone=+2:00:
When my application sends a date which has a timezone, does Oracle automatically translate the date to its dbtimezone and store it in the column?
When my application asks for a field date, does Oracle automatically translate it to the application timezone?
In order to be consistency with business rules, I wanted to change this dbtimezone to UTC. So I made the alter database set time_zone='UTC' command, I restarted the oracle server and now the select dbtimezone from dual; command returns "UTC".
But, all fields date in DB haven't changed (no change -2 hours from GMT+2 to UTC). When I ask the sysdate, it returns the GMT+2 date ... I try to change my SQL Developer configuration timezone to UTC but it didn't change anything. Do I have an issue of Oracle session parameters that convert my DB data to GMT+2 before displaying it ?
Finally, does anyone have a good practice to make this change ? (change the database timezone and existing date to a new timezone).
If all you're doing is changing the database time zone setting, then you are only going to notice any change in output if your data is stored with the TIMESTAMP WITH LOCAL TIME ZONE type.
I don't recommend that though. It would be much better if your data was just stored in a regular TIMESTAMP field and was already set to UTC.
You should read the documentation about all of the different date and time datatypes, so you understand how each of these types works and differs from the other.

Resources