to_date function AM PM Format - sql

Reading from a csv file using perl and inserting into a oracle table. In a particular csv field the date can be either in AM or PM format. So when i construct the to_date I am using AM / PM but it's giving me format code error. What formatcode needs to be provided in to_date to accept AM/PM Fields.
insert into invoices(invoice_id,invoice_date) values (2,to_date('2010-Aug-09 12:00:01 PM' , 'yyyy-Mon-dd HH:MI:SS AM / PM'));

You can specify either AM or PM. Try
SELECT to_date('2010-Aug-09 02:00:01 PM' , 'yyyy-Mon-dd HH:MI:SS AM') "date"
FROM dual;
SELECT to_date('2010-Aug-09 03:00:01 AM' , 'yyyy-Mon-dd HH:MI:SS PM') "date"
FROM dual;
Output:
| DATE |
---------------------------------
| August, 09 2010 14:00:01+0000 |
| DATE |
---------------------------------
| August, 09 2010 03:00:01+0000 |
Here SQLFiddle demo

Related

Not able to convert timestamp to char or date in oracle sql

I need to convert timestamp value(19-01-21 09:15:00.000000 PM) to date format('YYYY/MM/DD HH24:MI:SS') . I'm trying to do it using to_char function (to convert it to varchar and use it in TO_DATE function). I'm getting below error in to_char function. Is this the feasible way or please suggest if anything better works
select TO_CHAR('19-01-21 09:15:00.000000 PM','DD-MM-YY HH:MI:SSxFF AM') from dual;
select TO_DATE(TO_CHAR('19-01-21 09:15:00.000000 PM','DD-MM-YYYY HH:MI:SSxFF AM'),'YYYY/MM/DD HH24:MI:SS' ) from dual;
I'm getting below error:
ORA-01722: invalid number
01722. 00000 - "invalid number"
*Cause: The specified number was invalid.
*Action: Specify a valid number.
'19-01-21 09:15:00.000000 PM' is a string literal; it is not a DATE or TIMESTAMP data type.
Since your string has fractional seconds, you can use TO_TIMESTAMP to convert it to a TIMESTAMP data type:
SELECT TO_TIMESTAMP( '19-01-21 09:15:00.000000 PM', 'DD-MM-RR HH12:MI:SS.FF6 AM' )
AS timestamp_value
FROM DUAL;
Which outputs:
| TIMESTAMP_VALUE |
| :---------------------------- |
| 2021-01-19 21:15:00.000000000 |
If you want the value as a DATE data type then you can take the previous output and CAST it to a DATE:
SELECT CAST(
TO_TIMESTAMP( '19-01-21 09:15:00.000000 PM', 'DD-MM-RR HH12:MI:SS.FF6 AM' )
AS DATE
) AS date_value
FROM DUAL;
or, if the fractional seconds are always going to be zero:
SELECT TO_DATE( '19-01-21 09:15:00.000000 PM', 'DD-MM-RR HH12:MI:SS".000000" AM' )
AS date_value
FROM DUAL;
Which both output:
| DATE_VALUE |
| :------------------ |
| 2021-01-19 21:15:00 |
db<>fiddle here
I need to convert timestamp value to date/varchar value.
If you want to format the value as YYYY/MM/DD HH24:MI:SS then you can use TO_TIMESTAMP and then TO_CHAR:
SELECT TO_CHAR(
TO_TIMESTAMP( '19-01-21 09:15:00.000000 PM', 'DD-MM-RR HH12:MI:SS.FF6 AM' ),
'YYYY/MM/DD HH24:MI:SS'
) AS date_string
FROM DUAL;
Which outputs:
| DATE_STRING |
| :------------------ |
| 2021/01/19 21:15:00 |
(Note: this outputs a string data type and not a DATE data type; if you want a DATE data type then use the 2nd or 3rd example.)
db<>fiddle here

Converting a timestamp with Time zone to just a timestamp

Trying to insert some data into a a table. However, I tried i am receiving data compatibility issues. The column that I am trying to insert into is a timestamp(6) column while the column I am drawing data from is a timestamp with timezone column. I know how to use cast to convert from timestamp to a timestamp with timezone but not the inverse. Is there a way I can just strip out the 'UTC'?
Date I am starting out with:
'20-MAY-18 09.00.00.000000000 AM UTC'
Date I want to end up with:
'20-MAY-18 09.00.00.000000000 AM'
What I have tried thus far:
select to_date('20-MAY-18 09.00.00.000000000 AM UTC', 'dd-mon-yy hh:mi:ss A.M.') from dual;
However I receive an error, and I just can't seem to figure it out, what am I doing wrong? thanks in advance!
You can cast a timestamp with time zone to a plain timestamp:
cast(<your_value> as timestamp)
so with your value:
select cast(
to_timestamp_tz('20-MAY-18 09.00.00.000000000 AM UTC', 'DD-MON-RR HH:MI:SS.FF AM TZR')
as timestamp)
from dual;
CAST(TO_TIMESTAMP_T
-------------------
2018-05-20 09:00:00
If you insert as timestamp with tome zone value into a plain timestamp column then it will be converted automatically, just losing its tie zone information.
If the values might not always be UTC then you can convert them to UTC and to a plain timestamp in one go with sys_extract_tc():
with cte (tsz) as (
select timestamp '2018-05-20 09:00:00.0 UTC' from dual
union all select timestamp '2018-05-20 13:00:00.0 America/New_York' from dual
)
select tsz, cast(tsz as timestamp) as ts, sys_extract_utc(tsz) utc
from cte;
TSZ TS UTC
------------------------------ ------------------- -------------------
2018-05-20 09:00:00.000 +00:00 2018-05-20 09:00:00 2018-05-20 09:00:00
2018-05-20 13:00:00.000 -04:00 2018-05-20 13:00:00 2018-05-20 17:00:00

Oracle SQL: Handle with Daylight Saving Time

I have the following system information:
I use Oracle Database 10g
The SysTimeStamp is UTC
The SessionTimeZone is Europe/Athens
The dbTimeZone is +03:00
So, I have the column date_1 from tbl_1 table, with the following datetime:
date_1
-----------------
08.02.2017 10:00
08.02.2017 11:00
08.02.2017 12:00
-----------------
The results I want is like this:
date_2
-----------------
08.02.2017 13:00
08.02.2017 14:00
08.02.2017 15:00
For that I use:
SELECT TO_CHAR(date_1 + INTERVAL '3' HOUR, 'DD.MM.YYYY HH24:MI') as date_2
FROM tbl_1
WHERE date_1 >= TO_DATE('08.02.2017 10:00','DD.MM.YYYY HH24:MI')
AND date_1 <= TO_DATE('08.02.2017 12:00','DD.MM.YYYY HH24:MI')
My problem appear when the hour from March and October is changing because in the last Sunday from March we have 23 hours in a day and in the last Sunday from October we have 25 hours in a day.
Because of this I have to change my query 4 times/year (On summer time, on winter time, when we have 23 hour in March and when we have 25 hour in October)
Can you recommend a query in this select that solve this problem?
If you have a plain date or timestamp with no embedded time zone information, you can tell Oracle to treat it as being in a specific time zone with the from_tz() function. You can then convert that value - which now has data type 'timestamp with zone zone' rather than a plain 'timestamp' - to another zone with the at time zone datetime expression syntax, either using the session time zone as 'local' or with a specific named time zone:
alter session set nls_date_format='YYYY-MM-DD HH24:MI:SS';
alter session set nls_timestamp_format='YYYY-MM-DD HH24:MI:SS';
alter session set nls_timestamp_tz_format='YYYY-MM-DD HH24:MI:SS TZR';
alter session set time_zone = 'America/New_York';
with cte (ts) as (
select timestamp '2017-02-08 12:00:00' from dual
)
select ts,
from_tz(ts, 'UTC') as ts_utc,
from_tz(ts, 'UTC') at local as ts_local,
from_tz(ts, 'UTC') at time zone 'Europe/Athens' as ts_athens
from cte;
TS TS_UTC TS_LOCAL TS_ATHENS
------------------- ----------------------- ------------------------------------ ---------------------------------
2017-02-08 12:00:00 2017-02-08 12:00:00 UTC 2017-02-08 07:00:00 AMERICA/NEW_YORK 2017-02-08 14:00:00 EUROPE/ATHENS
If you're starting from a date then you have to convert it to a timestamp before calling from_tz():
with cte (dt) as (
select cast( timestamp '2017-02-08 12:00:00' as date) from dual
)
select dt,
from_tz(cast(dt as timestamp), 'UTC') as ts_utc,
from_tz(cast(dt as timestamp), 'UTC') at local as ts_local,
from_tz(cast(dt as timestamp), 'UTC') at time zone 'Europe/Athens' as ts_athens
from cte;
DT TS_UTC TS_LOCAL TS_ATHENS
------------------- ----------------------- ------------------------------------ ---------------------------------
2017-02-08 12:00:00 2017-02-08 12:00:00 UTC 2017-02-08 07:00:00 AMERICA/NEW_YORK 2017-02-08 14:00:00 EUROPE/ATHENS
So the data type of your original date_1 values matters, as does the nominal time zone it is supposed to represent. If it's a;ready a 'timestamp with time zone' or 'timestamp with local time zone' then it already has embedded time zone information, so you don't need the from_tz() part at all. If it's a date you need to convert it to a timestamp.
Assuming that date_1 is stored as a plain timestamp (maybe implied by your interval addition, but not by the column name and filters you used) and that it's nominally UTC, you could do:
from_tz(date_1, 'UTC') at time zone 'Europe/Athens'
... which will give you a 'timestamp with time zone' result; or you could use local to rely on your session time zone. If `date_1 is stored as a date you'd add the conversion to timestamp:
from_tz(cast(date_1 as timestamp), 'UTC') at time zone 'Europe/Athens'
As a demo, generating timestamps (not dates) in a CTE including some around the DST change for this year:
with tbl_1(date_1) as (
select timestamp '2017-02-08 10:00:00' from dual
union all select timestamp '2017-02-08 11:00:00' from dual
union all select timestamp '2017-02-08 12:00:00' from dual
union all select timestamp '2017-03-23 12:00:00' + numtodsinterval(level, 'day')
from dual connect by level <= 4
)
select date_1,
-- cast(from_tz(date_1, 'UTC') at time zone 'Europe/Athens' as timestamp) as date_2
to_char(from_tz(date_1, 'UTC') at time zone 'Europe/Athens',
'DD.MM.YYYY HH24:MI') as date_2
from tbl_1
order by date_1;
DATE_1 DATE_2
------------------- ----------------
2017-02-08 10:00:00 08.02.2017 12:00
2017-02-08 11:00:00 08.02.2017 13:00
2017-02-08 12:00:00 08.02.2017 14:00
2017-03-24 12:00:00 24.03.2017 14:00
2017-03-25 12:00:00 25.03.2017 14:00
2017-03-26 12:00:00 26.03.2017 15:00
2017-03-27 12:00:00 27.03.2017 15:00
You can see that an extra hour is added automatically after the clocks change on March 26th. But the results are out by an hour for your sample February data - so either your data isn't actually stored as UTC (but is -01:00, and you can change the from_tz() call to reflect that), or your expected results are wrong.
You can apply a case to the select:
select date_1 + case
when to_char(date_1 ,'MM') <= 3 then 2/24 -- Jan/Feb/Mar
when to_char(date_1,'MM') <= 10 then 3/24 -- Apr to Oct
else 2/24 -- Nov/Dec
end as date_2
from tbl_1
For USA timezone
SELECT SYSDATE,
NEXT_DAY ( TO_DATE (TO_CHAR (SYSDATE, 'YYYY') || '/03/01 02:00 AM', 'YYYY/MM/DD HH:MI AM') - 1, 'SUN') + 7 dst_start,
NEXT_DAY ( TO_DATE (TO_CHAR (SYSDATE, 'YYYY') || '/11/01 02:00 AM', 'YYYY/MM/DD HH:MI AM') - 1, 'SUN') dst_end,
CASE WHEN SYSDATE >= NEXT_DAY ( TO_DATE ( TO_CHAR (SYSDATE, 'YYYY') || '/03/01 02:00 AM', 'YYYY/MM/DD HH:MI AM') - 1, 'SUN') + 7 AND SYSDATE < NEXT_DAY ( TO_DATE ( TO_CHAR (SYSDATE, 'YYYY') || '/11/01 02:00 AM', 'YYYY/MM/DD HH:MI AM') - 1, 'SUN') THEN 'Y' ELSE 'N' END AS dst_check_usa,
NEW_TIME ( SYSDATE, CASE WHEN SYSDATE >= NEXT_DAY ( TO_DATE ( TO_CHAR (SYSDATE, 'YYYY') || '/03/01 02:00 AM', 'YYYY/MM/DD HH:MI AM') - 1, 'SUN') + 7 AND SYSDATE < NEXT_DAY ( TO_DATE ( TO_CHAR (SYSDATE, 'YYYY') || '/11/01 02:00 AM', 'YYYY/MM/DD HH:MI AM') - 1, 'SUN') THEN 'CDT' ELSE 'CST' END, 'GMT') AS current_time_gmt
FROM DUAL;
For Europe Timezone
SELECT SYSDATE,
NEXT_DAY(LAST_DAY(TO_DATE (TO_CHAR (SYSDATE, 'YYYY') || '/03/01 02:00 AM', 'YYYY/MM/DD HH:MI AM'))-7, 'SUN') dst_start_uk,
NEXT_DAY(LAST_DAY(TO_DATE (TO_CHAR (SYSDATE, 'YYYY') || '/10/01 02:00 AM', 'YYYY/MM/DD HH:MI AM'))-7, 'SUN') dst_end_uk,
CASE WHEN SYSDATE >= NEXT_DAY(LAST_DAY(TO_DATE (TO_CHAR (SYSDATE, 'YYYY') || '/03/01 02:00 AM', 'YYYY/MM/DD HH:MI AM'))-7, 'SUN') AND SYSDATE < NEXT_DAY(LAST_DAY(TO_DATE (TO_CHAR (SYSDATE, 'YYYY') || '/10/01 02:00 AM', 'YYYY/MM/DD HH:MI AM'))-7, 'SUN') THEN 'Y' ELSE 'N' END AS dst_check_uk
FROM DUAL;

Converting Oracle Date and Time

How do I convert the following timestamp in Oracle :
12-MAY-2013 12:00:00 AM
to this
11-MAY-2013 24:00:00
Thanks.
UPDATED A possible solution
SELECT CASE WHEN dt - TRUNC(dt) = 0
THEN TO_CHAR(TRUNC(dt) - 1, 'DD-Mon-YYYY') || ' 24:00:00'
ELSE TO_CHAR(dt, 'DD-Mon-YYYY HH24:MI:SS')
END dt
FROM
(
SELECT TO_DATE('12-MAY-2013 12:00:00 AM', 'DD-Mon-YYYY HH:MI:SS AM') dt
FROM dual
)
Output:
| DT |
------------------------
| 11-May-2013 24:00:00 |
Here is SQLFiddle demo
Original answer Try
SELECT TO_CHAR(TO_DATE('12-MAY-2013 12:00:00 AM', 'DD-Mon-YYYY HH:MI:SS AM'), 'DD-Mon-YYYY HH24:MI:SS') dt
FROM dual
Here is SQLFiddle demo
you cannot achieve this using standard Oracle functions. Oracle uses values 0 - 23, if you need to display midnight like 24:00, you have to write your own function.

Add 2 months to current timestamp

How can I add months to a timestamp value in Oracle? In my query, it's getting converted to date value instead:
SELECT add_months(current_timestamp,2)
FROM dual;
The actual output is:
ADD_MONTH
11-MAR-13
The expected output is:
2013-01-01 00:00:00.000000000+00:00
This will give you the date and the time as a TIMESTAMP data type:
select TO_TIMESTAMP(TO_CHAR(ADD_MONTHS(SYSDATE, 2), 'YYYYMMDD HH24:MI'),
'YYYYMMDD HH24:MI') from dual;
If you need more or less precision (E.G. rounding) than what is above, adjust the date formats (both need to be the same format). For example, this will return 2 months down to the seconds level of precision:
select TO_TIMESTAMP(TO_CHAR(ADD_MONTHS(SYSTIMESTAMP, 2),
'YYYYMMDD HH24:MI:SS'), 'YYYYMMDD HH24:MI:SS') from dual;
This is the closest I can get (as a character) to the format you need:
select TO_CHAR(
TO_TIMESTAMP(TO_CHAR(ADD_MONTHS(SYSTIMESTAMP, 2),
'YYYYMMDD HH24:MI:SS'), 'YYYY-MM-DD HH24:MI:SS'),
'YYYY-MM-DD HH24:MI:SS.FF TZR') from dual;
I think this will about give you what you're looking for:
SELECT TO_CHAR(TO_TIMESTAMP(ADD_MONTHS(CURRENT_TIMESTAMP,2))
+ (CURRENT_TIMESTAMP - TRUNC(CURRENT_TIMESTAMP)),
'YYYY-MM-DD HH:MI:SSxFFTZR') FROM DUAL;
The problem with using the interval methods is that you can get an unexpected error depending on the date you run the query. E.g.
SELECT TO_TIMESTAMP('31-JAN-2012') + NUMTOYMINTERVAL(1,'MONTH') FROM DUAL;
That query returns:
ORA-01839: date not valid for month specified
This is because it attempts to return February 31, which is not a valid date.
ADD_MONTHS is a "safer" way to date math, in that where the interval query would throw an error, ADD_MONTHS will return the last date of the month (Feb 28 or 29 depending on the year) in the above example.
For Oracle:
SELECT
TIMESTAMP'2014-01-30 08:16:32', -- TS we want to increase by 1 month
--TIMESTAMP'2014-01-30 08:16:32' + NUMTOYMINTERVAL(1, 'MONTH'), -- raises ORA-01839: date not valid for month specified
--TIMESTAMP'2014-01-30 08:16:32' + INTERVAL '1' MONTH, -- raises ORA-01839: date not valid for month specified
ADD_MONTHS(TIMESTAMP'2014-01-30 08:16:32', 1), -- works but is a date :(
CAST(ADD_MONTHS(TIMESTAMP'2014-01-30 08:16:32', 1) AS TIMESTAMP) -- works
FROM DUAL
SELECT current_timestamp + INTERVAL '2' MONTH from dual;
To display this in your desired format, use TO_CHAR:
SELECT TO_CHAR(current_timestamp + INTERVAL '2' MONTH,
'YYYY-MM-DD HH24:MI:SS.FF9TZH:TZM') from dual;
2013-03-11 23:58:14.789501000+01:00
For Oracle:
select TO_TIMESTAMP(Sysdate,'DD-Mon-YYYY HH24-MI-SS') + 60
from dual;
select sysdate + interval '2' month from dual;
select TO_TIMESTAMP (Sysdate + interval '2' month, 'DD-Mon-YYYY HH24-MI-SS')
from dual
;
Result1:
| TO_TIMESTAMP(SYSDATE,'DD-MON-YYYYHH24-MI-SS')+60 |
----------------------------------------------------
| March, 12 0013 00:00:00+0000 |
Result2:
| SYSDATE+INTERVAL'2'MONTH |
--------------------------------
| March, 11 2013 21:41:10+0000 |
Result3:
| TO_TIMESTAMP(SYSDATE+INTERVAL'2'MONTH,'DD-MON-YYYYHH24-MI-SS') |
------------------------------------------------------------------
| March, 11 0013 00:00:00+0000 |
sqlffidle demo.