Converting Oracle Date and Time - sql

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.

Related

Oracle Sql adding hours and minute to a to_date while insert statment

Hello I am trying to make an insert statement which includes adding 2 hours and 10 minutes to a to_date .
But i do not know which function i can use.
this is my statement so far
insert into xyz values (TO_DATE('22-Oct-2020 11:00 AM', 'DD-MM-YYYY HH:MI AM'))
but i want to add 2 hours and 10 minutes to the above while inserting.
Use date arithmetics. In Oracle, you can add decimal values to a date (1 stands for "1 day"):
insert into xyz
values (
to_date('22-Oct-2020 11:00 AM', 'DD-MM-YYYY HH:MI AM')
+ 2/24 + 10 / 60 / 24
)
Or:
insert into xyz
values (
to_date('22-Oct-2020 11:00 AM', 'DD-MM-YYYY HH:MI AM')
+ interval '2' hour + interval '10' minute
)
Or (with credits to Wernfried Domscheit):
insert into xyz
values (
to_date('22-Oct-2020 11:00 AM', 'DD-MM-YYYY HH:MI AM')
+ interval '2:10' hour to minute
)
You can use interval as well,
insert into xyz values (TO_DATE('22-Oct-2020 11:00 AM', 'DD-MM-YYYY HH:MI AM') + interval '130' minute);
select TO_DATE('22-Oct-2020 11:00 AM', 'DD-MM-YYYY HH:MI AM') + interval '130' minute from dual;
TO_DATE('22-OCT-202
-------------------
22-10-2020 01:10 PM
select TO_DATE('22-Oct-2020 11:00 AM', 'DD-MM-YYYY HH:MI AM') + interval '1' day from dual;
TO_DATE('22-OCT-202
-------------------
23-10-2020 11:00 AM

Generalize a query to fetch all the data for a given range

I have a select query which selects data between two date/time periods as below
SELECT *
FROM table1
WHERE table1 .row_creation > TO_DATE ('2017-04-03 11:00:00 AM','yyyy-mm-dd hh:mi:ss pm')
AND table1 .row_creation < TO_DATE('2017-04-04 03:00:00 AM','yyyy-mm-dd hh:mi:ss pm')
AND NOT EXISTS
(SELECT *
FROM table1
WHERE <cond>
AND table1 .row_creation > TO_DATE ('2017-04-03 11:00:00 AM','yyyy-mm-dd hh:mi:ss pm')
AND table1 .row_creation < TO_DATE('2017-04-04 03:00:00 AM','yyyy-mm-dd hh:mi:ss pm')
)
I want to modify this query to fetch the data for all consecutive weekdays in a month in one shot. Can anyone give me some guidance?
Add more columns in group by clause if you whant.
SELECT TO_CHAR(row_creation,'W')
FROM table1
WHERE
table1 .row_creation between TO_DATE ('2017-04-03 11:00:00 AM','yyyy-mm-dd hh:mi:ss pm') AND TO_DATE('2017-04-04 03:00:00 AM','yyyy-mm-dd hh:mi:ss pm')
AND NOT EXISTS
( SELECT *
FROM table1
WHERE
AND table1.row_creation BETWEEN TO_DATE ('2017-04-03 11:00:00 AM','yyyy-mm-
dd hh:mi:ss pm') AND TO_DATE('2017-04-04 03:00:00 AM','yyyy-mm-dd hh:mi:ss
pm')
)
AND TO_CHAR(row_creation,'DAY') NOT IN ('SATURDAY','SUNDAY')
GROUP BY TO_CHAR(row_creation,'W')
I think you can simplify this, for whole April 2017, like here:
select *
from (
select a.*,
count(case when cond='X' then 1 end) over (partition by trunc(row_creation-3/24)) cnt
from table1 a
where row_creation - 3/24 between date '2017-04-01' and date '2017-05-01'
and to_char(row_creation, 'hh24') not between '03' and '10')
where cnt = 0
where
row_creation - 3/24
assigns dates with hours 00:00 - 03:00 to previous day,
count(case when <cond> then 1 end) over (partition by trunc(row_creation - 3/24))
counts unwanted rows for this day, and finally:
where cnt = 0
is responsible for eliminating rows if there was at least one unwanted case for this day.
dbfiddle example

How to extract time from a date column in the where clause in ORACLE?

I want to select rows with a specific time interval but the date doesn't matter. So I need a function to return just the time part. I tried using:
to_char(mydate, 'HH12:MI:SS') between '00:00:00' and '08:00:00'
but this doesn't seem to work. Any ideas?
With some sample data you can see that using HH12 doens't necessarly produce the strings you are expecting:
alter session set nls_date_format = 'YYYY-MM-DD HH24:MI:SS';
-- CTE just for dummy data
with mytable (mydate) as (
select cast(timestamp '2018-08-01 00:00:00' as date) from dual
union all select cast(timestamp '2018-08-02 07:59:59' as date) from dual
union all select cast(timestamp '2018-08-03 08:00:00' as date) from dual
union all select cast(timestamp '2018-08-04 08:00:01' as date) from dual
union all select cast(timestamp '2018-08-05 19:59:59' as date) from dual
union all select cast(timestamp '2018-08-06 20:00:00' as date) from dual
union all select cast(timestamp '2018-08-07 20:00:01' as date) from dual
)
-- actual query
select mydate,
to_char(mydate, 'HH24:MI:SS') as time_24,
to_char(mydate, 'HH12:MI:SS') as time_12
from mytable;
MYDATE TIME_24 TIME_12
------------------- -------- --------
2018-08-01 00:00:00 00:00:00 12:00:00
2018-08-02 07:59:59 07:59:59 07:59:59
2018-08-03 08:00:00 08:00:00 08:00:00
2018-08-04 08:00:01 08:00:01 08:00:01
2018-08-05 19:59:59 19:59:59 07:59:59
2018-08-06 20:00:00 20:00:00 08:00:00
2018-08-07 20:00:01 20:00:01 08:00:01
So when you try to filter using that HH12-based string it includes records you don't expect to see, between 8am and 8pm; and also excludes midnight (as that is '12:00:00' not '00:00:00'):
select mydate
from mytable
where to_char(mydate, 'HH12:MI:SS') between '00:00:00' and '08:00:00';
MYDATE
-------------------
2018-08-02 07:59:59
2018-08-03 08:00:00
2018-08-05 19:59:59
2018-08-06 20:00:00
If you use HH24 instead then you get
select mydate
from mytable
where to_char(mydate, 'HH24:MI:SS') between '00:00:00' and '08:00:00';
MYDATE
-------------------
2018-08-01 00:00:00
2018-08-02 07:59:59
2018-08-03 08:00:00
Also, notice that between is inclusive, so it picks up records at exactly 08:00:00. That may not be what you want - if you're splitting the day into three 8-hour periods, you don't data for that second to be included multiple times; so you can use a more explicit range instead:
select mydate
from mytable
where to_char(mydate, 'HH24:MI:SS') >= '00:00:00'
and to_char(mydate, 'HH24:MI:SS') < '08:00:00';
MYDATE
-------------------
2018-08-01 00:00:00
2018-08-02 07:59:59
then your second shift is:
where to_char(mydate, 'HH24:MI:SS') >= '08:00:00'
and to_char(mydate, 'HH24:MI:SS') < '16:00:00';
and your third shift is:
where to_char(mydate, 'HH24:MI:SS') >= '16:00:00';
or if you prefer, for consistency:
where to_char(mydate, 'HH24:MI:SS') >= '16:00:00'
and to_char(mydate, 'HH24:MI:SS') < '24:00:00';
You can't ever get the hour reported as 24 but as it's a string comparison that doesn't matter here, though it is slightly jarring.
TO_CHAR(mydate, 'HH24:MI:SS')
WHERE mydate BETWEEN '00:00:00' AND '08: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;

to_date function AM PM Format

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