How to store timestamp with timezone - oracle

I am trying to store a timestamp with timezone into my oracle db.
I have for example this code:
$deadline = new \DateTime('2018-11-07 13:33', new \DateTimeZone("EUROPE/BERLIN"));
$control->setDeadline($deadline);
and the result stored in my oracle db is this one:
07.11.18 13:33:00.000000000 +01:00
but my goal is to to store the timestamp with this format: 07.11.18 13:33:00.000000000 EUROPE/BERLIN
if I run this query the value is correctly saved with the desired format:
update my_table
set deadline = TIMESTAMP '2018-11-07 09:00:00 EUROPE/BERLIN'
What I am doing wrong? What is the correct way to format the timestamp to obtain the desired result with symfony?

Looks like synfony transforms Europe/Berlin to +01:00 - which would be a bug.
As workaround you could do following:
ALTER SESSION SET TIME_ZONE = 'Europe/Berlin';
and then insert the value without any time zone, i.e.
$deadline = new \DateTime('2018-11-07 13:33');
$control->setDeadline($deadline);
If you insert a timestamp into a TIMESTAMP WITH TIME ZONE column and you don't provide any time zone information then Oracle defaults the time zone to your current SESSIONTIMEZONE which you set before.
You can set your SESSIONTIMEZONE also by Environment Variable ORA_SDTZ or in your Registry at HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\ORACLE\KEY_{ORACLE_HOME Name}\ORA_SDTZ, resp. HKEY_LOCAL_MACHINE\SOFTWARE\ORACLE\KEY_{ORACLE_HOME Name}\ORA_SDTZ

Related

Which time zone does the table's column of DATE data type reflect?

In Oracle database I have this table (the data type of column col is DATE):
col
2021-02-26 23:14:24
Question: in my case, assuming over time DB settings haven't changed, which time zone does the table's column of DATE data type reflect?
UTC or
Europe/Helsinki?
Following I provide current DB settings.
Database time zone
SELECT DBTIMEZONE FROM DUAL;
|DBTIMEZONE |
|============|
|+00:00 |
Session time zone
SELECT SESSIONTIMEZONE FROM DUAL;
|SESSIONTIMEZONE|
|===============|
|Europe/Helsinki|
SELECT CURRENT_DATE FROM DUAL;
|CURRENT_DATE |
|===================|
|2021-07-18 15:05:32|
The time zone of database server's operating system
SELECT SYSDATE FROM DUAL;
|SYSDATE |
|===================|
|2021-07-18 15:05:32|
SELECT SYSTIMESTAMP FROM DUAL;
|SYSTIMESTAMP |
|==============================|
|2021-07-18 15:05:32.984 +03:00|
The time zone is undefined by the column.
You can do:
CREATE TABLE table_name (col DATE);
ALTER SESSION SET TIME_ZONE = 'UTC';
INSERT INTO table_name (col) VALUES (CURRENT_DATE);
ALTER SESSION SET TIME_ZONE = 'Europe/Helsinki';
INSERT INTO table_name (col) VALUES (CURRENT_DATE);
ALTER SESSION SET TIME_ZONE = 'America/New_York';
INSERT INTO table_name (col) VALUES (CURRENT_DATE);
Then:
ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS';
SELECT * FROM table_name;
Outputs:
COL
2021-07-18 21:06:05
2021-07-19 00:06:05
2021-07-18 17:06:05
db<>fiddle here
Those values were all inserted in the same second by the same user in the same session using identical SQL statements; however there is no consistency in the time zone of the DATE value as the session settings were altered between each statement; so you cannot rely on a DATE having any particular time zone.
If you want to work out what time zone your data is in then check your application that is storing the data:
Is it always using SYSDATE? Then the time zone of the column is the time zone of the database's system.
Does the application specify the time zone? Then the data will have the time zone specified by the application.
Is it taking data from an external source? Then check that external source.
Is it taking data from the user? Then you have no guarantees.
If the data is of type DATE, then it doesn't reflect any time zone at all. It's just a date and time, with time resolved to the second. SYSDATE simply gets date and time from the host server OS, so to the degree that the time portion is reflective of any time zone, it would be that of the host OS.

Get the original Timezone from Postgres tstz field

I am having a table like this.
CREATE TABLE tstz (
ts timestamp NULL,
tstz timestamptz NULL,
seq text NULL
);
Whenever, I store the timestamp with time zone, it gets converted to the timezone of the database. How do I get back the original timezone with which it is retrieved?
For example, I am storing the timezone like 2020-04-29T08:06:03.424689+05:30 to the database. However, when I read the database using Java and read the timezone again like following.
Optional<Tstz> tstzOptionalSaved = tstzRepository.findById(tstz.getSeq());
Tstz tstzSaved = tstzOptionalSaved.get();
log.info("Timezone {}" , tstzSaved.getTstz().getZone().getId());
the above code always returns UTC which is the timezone of the database.
Is there a way to do this in Postgres or in Java?
You can use OffsetDateTime. From postgresql docs,
all OffsetDateTime will instances will have to be in UTC (have offset 0). This is because the backend stores them as UTC.
So you need to add one column for offset and then use the offset to get original value,
OffsetDateTime tstz = rs.getObject("tstz", OffsetDateTime.class);
OffsetDateTime odtOriginal = tstz
.toInstant()
.atOffset(ZoneOffset.ofTotalSeconds(rs.getInt("tstz_offset")));
// 2020-04-29T08:06:03.424689+05:30

Oracle database timestamp to timestamp with timezone

Need help in inserting the data from timestamp , to timestamp with zone.
create table foo ( tswtz TIMESTAMP WITH TIME ZONE);
SQL:>insert into foo values(systimestamp)
TSWTZ
---------------------------------------
09-08-16 11:39:21.199780000 AM +05:30
create table foo1 (test_dt timestamp)
insert into foo1 values(systimestamp)
TEST_DT
--------------------------------
09-08-16 11:40:55.242754000 AM
Now , there is a scenario, where i need to insert the values of foo1 to foo.
I have used the below command,
insert into foo (TSWTZ) (select CAST(TEST_DT AS TIMESTAMP WITH TIME ZONE) from foo1)
The select value displayed it as
09-08-16 11:40:55.242754000 AM ASIA/CALCUTTA
But it should display it as
09-08-16 11:40:55.242754000 AM +05:30.
Can you please help me on how to do that, without alter command ?
You need to alter your NLS parameters to get the result. Please read the oracle documentation as well [https://docs.oracle.com/cd/B19306_01/server.102/b14225/ch4datetime.htm][1]
Try setting:
NLS_TIMESTAMP_TZ_FORMAT = DD-MON-RR HH.MI.SSXFF AM TZR
and NLS_TIMESTAMP_FORMAT = DD-MON-RR HH.MI.SSXFF AM
and NLS_TIME_TZ_FORMAT = HH.MI.SSXFF AM TZR
and NLS_TIME_FORMAT = HH.MI.SSXFF AM
Function SYSTIMESTAMP returns current time in time zone of your database server operating system, in your case +05:30.
When you cast from TIMESTAMP (without any time zone information) to TIMESTAMP WITH TIME ZONE then Oracle takes your SESSIONTIMEZONE - unless you specify the time zone explicitly.
Obviously in your case the SESSIONTIMEZONE is set to Asia/Calcutta.
In order to get desired result you can do either
ALTER SESSION SET TIME_ZONE = '+05:30';
or
SELECT CAST((TEST_DT AT TIME ZONE '+05:30') AS TIMESTAMP WITH TIME ZONE)
FROM ...
Note, time zone Asia/Calcutta is different than +05:30, although the offset is the same. Region names like Asia/Calcutta considers daylight saving times (which does not apply for Asia/Calcutta), UTC offsets like +05:30 do not consider daylight saving times.

Timestamp to complete date format

We are working on oracle 11g enterprises edition. We are facing issue in getting value of date for type TIMESTAMPTZ and TIMESTAMPLTZ. We are storing those dates into one csv file using apache metamodel. We are fetching date from database using :
TIMESTAMPLTZ columnValue = (TIMESTAMPLTZ) row.getValues()[pos];
Timestamp timestamp=columnValue.timestampValue(connection,Calendar.getInstance(Locale.getDefault()));
Date dateByTimeStamp=new Date(timestamp.getTime());
Date dateByDateValue = columnValue.dateValue(connection);
String formattedDate = new SimpleDateFormat("dd-MMM-yy hh.mm.ss.SSSSSS a").format(dateByTimeStamp or dateByDateValue );
dateByDateValue contains date upto yyyy-mm-dd hh:mm:ss format. eg. 2016-10-12 08:49:30. There is no way to get value of nanoseconds and time zone using this object.
dateByTimeStamp object contains cdate that have value of date upto nanoseconds and also have time zone. But the value of date time differ because of time zone, but this cdate object contains information regarding nanoseconds precision.
Is there any way to get date in complete format so that the formatted date can directly be used to restore into another oracle db?

Is Postgres or Ruby adding the timezone to my `timestamp without time zone` column?

If I query my database with SELECT current_setting('TIMEZONE') I get 'UTC' (as expected).
Using PgAdmin, I run the following query:
SELECT foo FROM bar
PgAdmin shows "2011-03-12 08:00:00". However, when I read the value from Ruby (using DataMapper which uses the 'org.postgresql.Driver' JDBC driver as far as I know), it shows "2011-03-12 08:00:00 -0700".
Question: Where in the whole stack is the timezone getting added? Although I realize a lot depends on the specifics of my stack, it would really help to understand what should happen so that I can rule things out. For example, for a timestamp without time zone column, should I expect that JDBC driver gives a 'raw' value with no timezone information?
Something in Ruby is making the timezone adjustment:
psql=> select current_setting('timezone');
current_setting
-----------------
Canada/Pacific
(1 row)
psql=> select min(created_at) from people;
min
----------------------------
2010-07-09 13:58:51.320659
(1 row)
psql=> set timezone = 'utc';
psql=> select current_setting('timezone');
current_setting
-----------------
UTC
(1 row)
psql=> select min(created_at) from people;
min
----------------------------
2010-07-09 13:58:51.320659
(1 row)
You can check this by doing a raw SQL query of a timestamp from within Ruby and seeing what string you get back.
The JDBC driver when reading a timestamp without timezone makes bold/reasonable assumption that this timestamp is expressed in the JVM timezone.
If you do not want timezone to be added, use type 'timestamp without timezone'.
That way, reader will always read same second/hour/minute/day/month/year as you inserted.
I used following procedure to reproduce that
create table t (
without_tz timestamp without time zone ,
with_tz timestamp with time zone
)
SET SESSION TIME ZONE default;
insert into t VALUES ( now(), now() )
select * from t;
SET SESSION TIME ZONE PST8PDT;
insert into t VALUES ( now(), now() )
select * from t;
SET SESSION TIME ZONE PST6PDT;
insert into t VALUES ( now(), now() )
select * from t;
Observing values from select, I come to conclusion that
timestamp without timezone is never converted. You read same second/hour/minute/day/month/year what you inserted, no matter what timezone you are in.
timestamp with timezone converts values you read to your timezone. they represent same instant (point in time) but hour (and sometimes days, sometimes even minutes) values will be diffrent.

Resources