Oracle subtracting days and minutes - oracle

I want to subtract "X" days and "X" minutes from sysdate, where the days and minutes are an integer as input parameter. For instance, 10 days and 5 minutes.
I found many examples to subtract either minutes or hours but not a combination of days and minutes.
select sysdate - 5 / 24 / 60 from dual -- will retrieve sysdate minus 5 minutes.
--What about the days?
Thank you!

Use an interval literal:
SELECT SYSDATE - INTERVAL '10 00:05' DAY(2) TO MINUTE
FROM DUAL
Or:
SELECT SYSDATE - INTERVAL '10' DAY - INTERVAL '5' MINUTE
FROM DUAL
Or just use arithmetic:
SELECT SYSDATE - 10 /* Days */ - 5 / 24 /60 /* Minutes */
FROM DUAL
Or use NUMTODSINTERVAL:
SELECT SYSDATE - NUMTODSINTERVAL( 10, 'DAY' ) - NUMTODSINTERVAL( 5, 'MINUTE' )
FROM DUAL

You can use Interval day to minute - http://docs.oracle.com/cd/B19306_01/server.102/b14200/sql_elements003.htm#i38598
select sysdate - interval '1 00:05' day to minute from dual

Related

Calculate only working hours between dates in ORACLE

Hello everyone I have written an oracle query which is calculating working according to 8 hours, but I want according to 8.5 hours result, there is a minor change but I am not getting it please help. Now according to the start and end date, it should return 8.5 working house, but it is returning 8 working hours please assist.
Query
with dates as (
select to_date('20-oct-2022 09:00:00','dd-mon-yyyy hh24:mi:ss') start_dt,
to_date('20-oct-2022 17:30:00','dd-mon-yyyy hh24:mi:ss') end_dt
from dual
),
-- get work hours for each date
t as (
select case level
when 1 then greatest(start_dt,trunc(start_dt) + 8 / 24)
else trunc(start_dt) + level - 16 / 24
end start_dt,
case connect_by_isleaf
when 1 then least(end_dt,trunc(end_dt) + 17 / 24)
else trunc(start_dt) + level - 7 / 24
end end_dt
from dates
connect by level <= trunc(end_dt) - trunc(start_dt) + 1
)
select sum(greatest(end_dt - start_dt,0)) * 24 work_hours
from t
where trunc(start_dt) - trunc(start_dt,'iw') < 5
You do not need to generate all the days; you can directly calculate the number of hours:
SELECT start_dt,
end_dt,
ROUND(
(
-- Calculate the full weeks difference from the start of ISO weeks.
( TRUNC( end_dt, 'IW' ) - TRUNC( start_dt, 'IW' ) ) * 8.5 * (5/7)
-- Add the full days for the final week.
+ LEAST( TRUNC( end_dt ) - TRUNC( end_dt, 'IW' ), 5 ) * 8.5
-- Subtract the full days from the days of the week before the start date.
- LEAST( TRUNC( start_dt ) - TRUNC( start_dt, 'IW' ), 5 ) * 8.5
-- Add the hours of the final day
+ CASE
WHEN end_dt - TRUNC( end_dt, 'IW' ) < 5 -- Weekday
THEN LEAST(
GREATEST(
end_dt - (TRUNC( end_dt ) + INTERVAL '09:00' HOUR TO MINUTE),
0
) * 24,
8.5
)
ELSE 0
END
-- Subtract the hours of the day before the range starts.
- CASE
WHEN start_dt - TRUNC( start_dt, 'IW' ) < 5 -- Weekday
THEN LEAST(
GREATEST(
start_dt - (TRUNC( start_dt ) + INTERVAL '09:00' HOUR TO MINUTE),
0
) * 24,
8.5
)
ELSE 0
END
),
15 -- Number of decimal places
) AS work_hours_diff
FROM dates;
Which, for the sample data:
CREATE TABLE dates (start_dt, end_dt) AS
SELECT DATE '2022-10-20' + INTERVAL '09:00:00' HOUR TO SECOND,
DATE '2022-10-20' + INTERVAL '17:30:00' HOUR TO SECOND
FROM DUAL
UNION ALL
SELECT DATE '2022-10-20' + INTERVAL '10:00:00' HOUR TO SECOND,
DATE '2022-10-21' + INTERVAL '17:30:00' HOUR TO SECOND
FROM DUAL
UNION ALL
SELECT DATE '2022-11-19' + INTERVAL '23:46:00' HOUR TO SECOND,
DATE '2022-11-21' + INTERVAL '12:06:00' HOUR TO SECOND
FROM DUAL
UNION ALL
SELECT DATE '2022-11-18' + INTERVAL '17:30:00' HOUR TO SECOND,
DATE '2022-11-21' + INTERVAL '09:00:00' HOUR TO SECOND
FROM DUAL
UNION ALL
SELECT DATE '2022-11-19' + INTERVAL '12:26:45' HOUR TO SECOND,
DATE '2022-11-21' + INTERVAL '11:02:15' HOUR TO SECOND
FROM DUAL
UNION ALL
SELECT DATE '2022-11-21' + INTERVAL '11:02:15' HOUR TO SECOND,
DATE '2022-11-19' + INTERVAL '12:26:45' HOUR TO SECOND
FROM DUAL;
Outputs:
START_DT
END_DT
WORK_HOURS_DIFF
2022-10-20 09:00:00 (THU)
2022-10-20 17:30:00 (THU)
8.5
2022-10-20 10:00:00 (THU)
2022-10-21 17:30:00 (FRI)
16
2022-11-19 23:46:00 (SAT)
2022-11-21 12:06:00 (MON)
3.1
2022-11-18 17:30:00 (FRI)
2022-11-21 09:00:00 (MON)
0
2022-11-19 12:26:45 (SAT)
2022-11-21 11:02:15 (MON)
2.0375
2022-11-21 11:02:15 (MON)
2022-11-19 12:26:45 (SAT)
-2.0375
Note: the negative value is valid as the start date is after the end date for that row.
fiddle

Time in oracle with crossing over 0:00

can you help me please.
I'm use:
round((24 * 60 * (to_date(EndPick, 'HH24:MI') - to_date(StartPick, 'HH24:MI'))), 2) as WorkTime
All time EndPick bigger then StartPick. But we have a chance, what Start bigger where
estimate time interval if there is a crossing over 00:00 into the next date?
In relult for example:
3
(minutes)
But we have a chance, what Start bigger where estimate time interval if there is a crossing over 00:00 into the next date?
Use a CASE expression and add a day if startpick > endpick:
SELECT round(
(24 * 60 * (to_date(EndPick, 'HH24:MI')
+ CASE
WHEN startpick > endpick
THEN INTERVAL '1' DAY
ELSE INTERVAL '0' DAY
END
- to_date(StartPick, 'HH24:MI')
)),
2
) as WorkTime
FROM table_name;
Which, for the sample data:
CREATE TABLE table_name (startpick, endpick) AS
SELECT '00:00', '01:00' FROM DUAL UNION ALL
SELECT '23:00', '00:00' FROM DUAL;
Outputs:
WORKTIME
60
60
fiddle

Use EPOCH time for timestamp to get records within 1 minute

I was curious to see how in Oracle 12c you can take a timestamp datatype and convert the records into EPOCH time to make them a number and then use that number to find any records within that date column that are within 1 minute of each other (assuming the same day if needed, or simply any calculations within 1 minute).
I tried the following but got an ORA-01873: the leading precision of the interval is too small error.
select (sold_date - to_date('1970-01-01 00:00:00','YYYY-MM-DD HH24:MI:SS'))*86400 as epoch_sold_date from test1;
What is SOLD_DATE? For e.g. SYSDATE (function that returns DATE datatype), your code works OK.
SQL> select (sysdate
2 - to_date('1970-01-01 00:00:00','YYYY-MM-DD HH24:MI:SS')
3 ) * 86400 as epoch_sold_date
4 from dual;
EPOCH_SOLD_DATE
---------------
1600807918
SQL>
As SOLD_DATE is a timestamp, but - it appears that fractions of a second aren't or special interest to you, cast it to DATE:
select (cast (systimestamp as date) --> this
- to_date('1970-01-01 00:00:00','YYYY-MM-DD HH24:MI:SS')
) * 86400 as epoch_sold_date
from dual;
Saying that you get the same result for all rows: well, I don't, and you shouldn't either if SOLD_DATE differs.
SQL> with test (sold_date) as
2 (select timestamp '2020-09-22 00:00:00.000000' from dual union all
3 select timestamp '2015-03-18 00:00:00.000000' from dual
4 )
5 select sold_date,
6 (cast (sold_date as date)
7 - to_date('1970-01-01 00:00:00','YYYY-MM-DD HH24:MI:SS')
8 ) * 86400 as epoch_sold_date
9 from test;
SOLD_DATE EPOCH_SOLD_DATE
------------------------------ ---------------
22.09.20 00:00:00,000000000 1600732800
18.03.15 00:00:00,000000000 1426636800
SQL>
One more edit: when you subtract two timestamps, result is interval day to second. If you extract minutes from it, you get what you wanted:
SQL> with test (sold_date) as
2 (select timestamp '2020-09-22 10:15:00.000000' from dual union all
3 select timestamp '2015-03-18 08:05:00.000000' from dual
4 )
5 select sold_date,
6 lead(sold_date) over (order by sold_date) next_sold_date,
7 --
8 lead(sold_date) over (order by sold_date) - sold_date diff,
9 --
10 extract(day from lead(sold_date) over (order by sold_date) - sold_date) diff_mins
11 from test
12 order by sold_date;
SOLD_DATE NEXT_SOLD_DATE DIFF DIFF_MINS
------------------------------ ------------------------------ ------------------------------ ----------
18.03.15 08:05:00,000000000 22.09.20 10:15:00,000000000 +000002015 02:10:00.000000000 2015
22.09.20 10:15:00,000000000
SQL>
In your case, you'd check whether extracted minutes value is larger than 1 (minute).
If you just want to see how many minutes are there between two timestamps, then
cast them to dates
subtract those dates (and you'll get number of days)
multiply it by 24 (as there are 24 hours in a day) and by 60 (as there are 60 minutes in an hour)
Something like this:
SQL> with test (date_1, date_2) as
2 (select timestamp '2020-09-22 10:15:00.000000',
3 timestamp '2020-09-22 08:05:00.000000' from dual
4 )
5 select (cast(date_1 as date) - cast(date_2 as date)) * 24 * 60 diff_minutes
6 from test;
DIFF_MINUTES
------------
130
SQL>
If you are just looking to compare dates and find rows that are within one minute of each other, you do not need to use epoch time. There are several solutions to this problem on this thread.

Oracle sysdate flexible date

I worked this statement out
SELECT to_date('30.06.2016', 'dd.mm.yyyy') - (LEVEL-1) DATUM
FROM DUAL
CONNECT BY LEVEL <= 366;
which gives me all dates from 30.06.2016 till 366 days in the past.
So far so good.
What I need to add is that to_date('30.06.2016') is more flexible..
What I mean I always want it to use the last day of June in sysdate + 1 year.
In this case we have 2015 at the moment - so we have 30.06.2016.
If we had 2016 I need it to use 30.06.2017.
If we had 2017 I need it to use 30.06.2018.
..
..
Thanks for your help.
EDIT Solution:
SELECT last_day(add_months(to_date('01.06.' || to_char(sysdate, 'YYYY'), 'dd.mm.yyyy'),12)) - (LEVEL-1) DATUM
FROM DUAL
CONNECT BY LEVEL <= 366
If you want 366 days worth of dates:
SELECT TRUNC( SYSDATE, 'YEAR' ) + INTERVAL '18' MONTH - LEVEL AS DATUM
FROM DUAL
CONNECT BY LEVEL <= 366;
Or if you want a year's worth (365 days or 366 days in a leap year) of dates (1st July this year to 30th June next year):
SELECT TRUNC( SYSDATE, 'YEAR' ) + INTERVAL '18' MONTH - LEVEL AS DATUM
FROM DUAL
CONNECT BY TRUNC( SYSDATE, 'YEAR' ) + INTERVAL '18' MONTH - LEVEL >= TRUNC( SYSDATE, 'YEAR' ) + INTERVAL '6' MONTH;
Is your same code, but get from sysdate the year, using to_char:
select to_date('30.06.'||(to_char(sysdate,'yyyy')+1),'dd.mm.yyyy') from dual;
Here's the steps:
Truncate sysdate to the year, using Trunc().
Add 18 months, using Add_Months().
Subtract one day.

How to find the time difference with respect to date in Oracle?

I want to find the time difference between the value in the column of type Date and the fixed time of that particular date.
Consider,
value in column - 4/16/2011 4:00:19 PM
Fixed time as - 3:00:00 PM
I am expecting the answer as 1hr 0min 19sec ago. Whatever the type I'm ok with it.
Thanks
Since you don't care what data type is returned, I'd probably cast to a timestamp so that you can get an interval day to second returned.
SQL> select cast( sysdate as timestamp ) from dual
2 ;
CAST(SYSDATEASTIMESTAMP)
---------------------------------------------------------------------------
15-MAR-15 04.05.46.000000 PM
SQL> ed
Wrote file afiedt.buf
1 select cast( sysdate as timestamp ) -
2 cast( trunc(sysdate) + interval '15' hour as timestamp )
3* from dual
4 /
CAST(SYSDATEASTIMESTAMP)-CAST(TRUNC(SYSDATE)+INTERVAL'15'HOURASTIMESTAMP)
---------------------------------------------------------------------------
+000000000 01:06:18.000000
If you want to return a string rather than an interval, you can use extract to extract data from the interval
SQL> ed
Wrote file afiedt.buf
1 select extract( hour from delta ) || ' hours, ' ||
2 extract( minute from delta ) || ' minutes, ' ||
3 extract( second from delta ) || ' seconds ago'
4 from (
5 select cast( sysdate as timestamp ) -
6 cast( trunc(sysdate) + interval '15' hour as timestamp ) delta
7 from dual
8* )
SQL> /
EXTRACT(HOURFROMDELTA)||'HOURS,'||EXTRACT(MINUTEFROMDELTA)||'MINUTES,'||EXTRACT(
--------------------------------------------------------------------------------
1 hours, 10 minutes, 46 seconds ago

Resources