How to update a TIMESTAMP column to TIMESTAMP WITH TIME ZONE in Oracle - oracle

I have a pair of columns that were unfortunately defined incorrectly as TIMESTAMP(6) instead of TIMESTAMP(6) WITH TIME ZONE. I would like to migrate those columns from the old, wrong datatype to the new, correct one. On top of that, the values appear to have been captured in E(S|D)T and I need the value in UTC.
So far, the best I've got is:
alter table OOPSIE_TABLE add (
NEW_COLUMN_A timestamp(6) with time zone,
NEW_COLUMN_B timestamp(6) with time zone
);
update OOPSIE_TABLE set
NEW_COLUMN_A = COLUMN_A,
NEW_COLUMN_B = COLUMN_B
;
alter table OOPSIE_TABLE drop column (
COLUMN_A,
COLUMN_B
);
alter table OOPSIE_TABLE rename column NEW_COLUMN_A to COLUMN_A;
alter table OOPSIE_TABLE rename column NEW_COLUMN_B to COLUMN_B;
Unfortunately, that leaves me with data that looks like 15-JUN-12 05.46.29.600102000 PM -04:00, when I want 15-JUN-12 09.46.29.600102000 PM UTC (or however Oracle would format it).
I've done select dbtimezone from dual; and it shows me +00:00, so I'm not sure how to proceed. Ideally, I would be able to do this in pure DML, and have it account for DST based on the old date values (which I'm sure are in the America/New_York timezone).

With a little help from #JustinCave, I arrived at the following solution, which accomplishes exactly what I wanted:
-- Rename the old columns so we can use them as a data source *AND* so
-- we can roll back to them if necessary.
alter table OOPSIE_TABLE rename column COLUMN_A to OLD_COLUMN_A;
alter table OOPSIE_TABLE rename column COLUMN_B to OLD_COLUMN_B;
-- Define COLUMN_A and COLUMN_B to have TIME ZONE support.
alter table OOPSIE_TABLE add (
COLUMN_A timestamp(6) with time zone,
COLUMN_B timestamp(6) with time zone
);
-- Populate the "new" columns with the adjusted version of the old data.
update OOPSIE_TABLE set
COLUMN_A = from_tz(OLD_COLUMN_A, 'America/New_York') at time zone 'UTC',
COLUMN_B = from_tz(OLD_COLUMN_B, 'America/New_York') at time zone 'UTC'
;

For me it looks good.
`SELECT SYS_EXTRACT_UTC(TIMESTAMP '2012-06-15 05:46:20 -04:00') FROM DUAL;`
gives:
2012-06-15 09:46:20
You simply live in country with 4 hour difference to UTC.
Also try something like:
SELECT to_char(new_column_a, 'YYYY-MM-DD HH24:MI:SS TZD'), sys_extract_utc(new_column_a) FROM oopsie_table;

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.

Oracle SQL Developer- How to force 00:00:00 hour when inserting a new DATE value

In my Oracle SQL Developer, i have a table with a column with DATE format. When i insert a new row into this table, and insert a new value in this column, it automatically suggestes me the current date with the current hour.
I would like that it automatically suggestes me current date, but with 00:00:00 hour . Is there some setting or parameter that i can set in my SQL Developer to have this result?
We can't able to insert 00:00:00 hours ... the hour value should be between 1 to 12...
we can use below query to insert 00:00:00 hours but the value will be changed to 12:00:00
INSERT INTO TABLE (DATE_COL) VALUES
( TO_DATE ('11/16/2017 00:00:00 ', 'MM/DD/YYYY HH24:MI:SS '));
It seems to me that your DATE column is set with a DEFAULT of SYSDATE. This means, for any INSERT operations which do not specify a value in your DATE column, the current date and time will populate for that row. However, if INSERT operations do specify a value in your DATE column, then the specified date value will supersede the DEFAULT of SYSDATE.
If an application is controlling INSERT operations on that table, then one solution is to ensure the application utilizes the TRUNC() function to obtain your desired results. For example:
INSERT INTO tbl_target
(
col_date,
col_value
)
VALUES
(
TRUNC(SYSDATE, 'DDD'),
5000
)
;
However, if there are multiple applications or interfaces where users could be inserting new rows into the table, (e.g. using Microsoft Access or users running INSERT statements via SQL Developer) and you can't force all of those interfaces to utilize the TRUNC() function on that column during insertion, then you need to look into other options.
If you can ensure via applications that INSERT operations will not actually reference the DATE, then you can simply ALTER the table so that the DATE column will have a DEFAULT of TRUNC(SYSDATE). A CHECK CONSTRAINT can be added for further integrity:
ALTER TABLE tbl_target
MODIFY
(
col_date DATE DEFAULT TRUNC(SYSDATE, 'DDD') NOT NULL
)
ADD
(
CONSTRAINT tbl_target_CHK_dt CHECK(col_date = TRUNC(col_date, 'DDD'))
)
;
However, if users still have the freedom to specify the DATE when inserting new rows, you will want to use a TRIGGER:
CREATE OR REPLACE TRIGGER tbl_target_biu_row
BEFORE INSERT OR UPDATE OF col_val
ON tbl_target
FOR EACH ROW
BEGIN
:NEW.col_date := TRUNC(SYSDATE, 'DDD');
END tbl_target_biu_row
;
This will take of needing to manage the application code of all external INSERT operations on the table. Keep in mind, the above trigger is also modifying the DATE column if a user updates the specified value column.

how to change the date to time in oracle 10g

I have to put in STIMING a time when I insert I use TO_DATE function but it give me date not time and it should be time.
This is the table and the code that i use
SQL> select * from shift;
SNO SNAME STIMING
---------- -------------------- ---------
121323 morning 01-APR-17
112232 evening 01-APR-17
665342 afternoon 01-APR-17
SQL> update shift
2 set STIMING= ('07:00:00 HH,MI,SS')
3 where SNO=121323;
set STIMING= ('07:00:00 HH,MI,SS')
*
ERROR at line 2:
ORA-01843: not a valid month
I have to put in STIMING a time
Oracle does not have a TIME datatype. The DATE data type is always stored internally as 7-bytes and is always composed of year (2-bytes) and month, day, hours, minutes and seconds (1-byte each).
You cannot not have a year, month or day component of a DATE.
If you want a time on its own then you will have to store it as a different data type or store the year/month/day and ignore that component.
When you are SELECTing the STIMING column it is not showing the time component. You can change this by changing the default date format which is set in the NLS_DATE_FORMAT session parameter.
You can review this parameter using:
SELECT VALUE FROM NLS_SESSION_PARAMETERS WHERE PARAMETER = 'NLS_DATE_FORMAT';
You can set this value within your current session using:
ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS';
(Note: this does not change the value for any other users.)
When you insert the date you can use:
INSERT INTO shift ( SNO, SNAME, STIMING)
VALUES ( 121323, 'morning', TO_DATE( '01-APR-2017 07:00' DD-MON-YYYY HH24:MI' ) )
Or, an ANSI TIMESTAMP literal (which will be implicitly cast to the DATE format of the column):
INSERT INTO shift ( SNO, SNAME, STIMING)
VALUES ( 121323, 'morning', TIMESTAMP '2017-04-01 07:00:00' )
I suggest you to avoid updates, change your insert part from to_date with no formatting param to to_date( colname, 'DD-MON-YY HH24:MI:SS')

select data based on a date column

I was trying to select some data from my table using the following query:
select * from table1 where column1 = to_date('14-05-14','yy-mm-dd');
Where the column data type is DATE. I observed that, the above query won't return anything unless we modified it as,
select * from table1 where trunc(column1) = to_date('14-05-14','yy-mm-dd');
even though there are records available.
I checked the documentation for TRUNC.Can anyone please explain why this happens?
UPDATE
As per the valuable comments I think some time values may also associated with the DATE. But I cannot view/edit that time. How can I ensure there are time values associated.
Both TO_DATE and TRUNC are different. See the below example.
SQL> ALTER SESSION SET nls_date_format = 'dd/mm/yyyy hh24:mi:ss';
Session altered.
SQL> SELECT TO_DATE(SYSDATE) FROM DUAL;
TO_DATE(SYSDATE)
-------------------
28/05/2014 16:03:25
SQL> SELECT TRUNC(SYSDATE) FROM DUAL;
TRUNC(SYSDATE)
-------------------
28/05/2014 00:00:00
In Your first query to_date('14-05-14','yy-mm-dd') is comparing with the date field column1 in your table which has time values also. Whereas in Your 2nd query You are truncating the time part from table data and from Your query, that's why it's matching.
The DATE datatype stores the year (including the century), the month, the day, the hours, the minutes, and the seconds (after midnight).
TRUNC function will truncate the date to the day value, so that any hours, minutes, or seconds will be truncated off.
For more info please look at these below links
http://docs.oracle.com/cd/B28359_01/server.111/b28318/datatype.htm#CNCPT413
http://www.techonthenet.com/oracle/functions/trunc_date.php

how to insert date and time in oracle?

Im having trouble inserting a row in my table. Here is the insert statement and table creation. This is part of a uni assignment hence the simplicity, what am i doing wrong? Im using oracle SQL developer Version 3.0.04.'
The problem i am having is that it is only inserting the dd/mon/yy but not the time. How do i get it to insert the time as well?
INSERT INTO WORKON (STAFFNO,CAMPAIGNTITLE,DATETIME,HOURS)
VALUES ('102','Machanic Summer Savings',TO_DATE('22/April/2011 8:30:00AM','DD/MON/YY HH:MI:SSAM'),'3')
;
CREATE TABLE WorkOn
(
StaffNo NCHAR(4),
CampaignTitle VARCHAR(50),
DateTime DATE,
Hours VARCHAR(2)
)
;
Thanks for the help.
EDIT: This is making no sense, i enter just a time in the field to test if time is working and it outputs a date WTF? This is really weird i may not use a date field and just enter the time in, i realise this will result in issues manipulating the data but this is making no sense...
You can use
insert into table_name
(date_field)
values
(TO_DATE('2003/05/03 21:02:44', 'yyyy/mm/dd hh24:mi:ss'));
Hope it helps.
You are doing everything right by using a to_date function and specifying the time. The time is there in the database. The trouble is just that when you select a column of DATE datatype from the database, the default format mask doesn't show the time. If you issue a
alter session set nls_date_format = 'dd/MON/yyyy hh24:mi:ss'
or something similar including a time component, you will see that the time successfully made it into the database.
Try this:
...(to_date('2011/04/22 08:30:00', 'yyyy/mm/dd hh24:mi:ss'));
Just use TO_DATE() function to convert string to DATE.
For Example:
create table Customer(
CustId int primary key,
CustName varchar(20),
DOB date);
insert into Customer values(1,'Vishnu', TO_DATE('1994/12/16 12:00:00', 'yyyy/mm/dd hh:mi:ss'));
create table Customer(
CustId int primary key,
CustName varchar(20),
DOB date);
insert into Customer values(1,'kingle', TO_DATE('1994-12-16 12:00:00', 'yyyy-MM-dd hh:mi:ss'));

Resources