PL/SQL: TO_CHAR show format - oracle

So I have this code here:
create or replace FUNCTION calc_length(
START_TIME IN number,
FINISH_TIME IN number
) RETURN NUMBER IS
BEGIN
RETURN ( (FINISH_TIME - START_TIME ) ;
END
And I want to show the result in the format as H:mm
I tried TO_CHAR function but it accepts a strict preset formats.

Few examples - copy, paste to see the oputput:
SELECT trunc(mydate / 3600) hr
, trunc(mod(mydate, 3600) / 60) mnt
, trunc(mod(mydate, 3600) / 60 /60) sec
FROM
(
SELECT (to_date('01/02/2013 23:00:00', 'mm/dd/yyyy hh24:mi:ss') -
to_date('01/01/2013 07:00:00', 'mm/dd/yyyy hh24:mi:ss')) * 86400 mydate
FROM dual
)
/
Select hh, mi, ss From
(
Select EXTRACT(hour From Cast(SYSDATE as timestamp)) hh,
EXTRACT(minute From Cast(SYSDATE as timestamp)) mi,
EXTRACT(second From Cast(SYSDATE as timestamp)) ss
From dual
)
/
Select start_date, end_date, time_diff,
EXTRACT(DAY FROM time_diff) days,
EXTRACT(HOUR FROM time_diff) hours,
EXTRACT(MINUTE FROM time_diff) minutes,
EXTRACT(SECOND FROM time_diff) seconds
From
(
Select start_date, end_date, end_date - start_date time_diff
From
(
Select CAST(to_date('21/02/2012 06:10:53 am', 'dd/mm/yyyy hh:mi:ss am') AS TIMESTAMP) end_date
, CAST(to_date('21/02/2012 12:05:00 am', 'dd/mm/yyyy hh:mi:ss am') AS TIMESTAMP) start_date
From dual
))
/

Related

I would like to find the Hours between two date time and need to exclude weekend hours( saturday & sunday) without function and procedure

i need to find the processing hours for below data between start and end date and i need to exclude saturday and sunday in between those dates
Sample data
Query i use for finding hours but not able to find the weekend calculation
SELECT
name,
StartDate,
EndDate,
to_char(StartDate, 'dd/mm/yyyy hh24:mi:ss') StartDate,
to_char(EndDate, 'dd/mm/yyyy hh24:mi:ss') EndDate,
to_char(datediff('hh', StartDate, EndDate), 'fm9999999.90') hours
FROM
MyTable
WHERE
StartDate > '01/01/2022'
AND EndDate < '08/08/2022'
ORDER BY
StartDate DESC;
Although there us no datediff command for Oracle here is an implementation, which can be used.
create or replace function datediff( p_what in varchar2, p_d1 in date, p_d2 in date ) return number
as
l_result number;
begin
select (p_d2-p_d1) *
decode( upper(p_what),
'SS', 24*60*60, 'MI', 24*60, 'HH', 24, NULL )
into l_result from dual;
return l_result;
end;
/
select datediff( 'ss',
to_date('01-AUG-2022 12:02:04', 'dd-mon-yyyy hh24:mi:ss'),
to_date('09-AUG-2022 18:22:34', 'dd-mon-yyyy hh24:mi:ss' )) seconds FROM DUAL;
SECONDS
714029.9999999999999999999999999999999999
select datediff( 'mi',
to_date('01-AUG-2022 12:02:04', 'dd-mon-yyyy hh24:mi:ss'),
to_date('09-AUG-2022 18:22:34', 'dd-mon-yyyy hh24:mi:ss' )) minutes FROM DUAL;
MINUTES
11900.5
select datediff( 'hh',
to_date('01-AUG-2022 12:02:04', 'dd-mon-yyyy hh24:mi:ss'),
to_date('09-AUG-2022 18:22:34', 'dd-mon-yyyy hh24:mi:ss' )) hours FROM DUAL;
HOURS
198.341666666666666666666666666666666667
CREATE TABLE table_name (name, startdate, enddate) AS
SELECT 'DOC1', TIMESTAMP '2022-08-15 09:00:00',
TIMESTAMP '2022-08-15 17:00:00' FROM DUAL UNION ALL
SELECT 'DOC2', TIMESTAMP'2022-08-16 09:00:00',
TIMESTAMP '2022-08-16 17:00:00' FROM DUAL UNION ALL
SELECT 'DOC3', TIMESTAMP '2022-08-17 09:00:00',
TIMESTAMP '2022-08-17 17:00:00' FROM DUAL UNION ALL
SELECT 'DOC4', TIMESTAMP '2022-08-18 09:00:00',
TIMESTAMP '2022-08-18 17:00:00' FROM DUAL UNION ALL
SELECT 'DOC5', TIMESTAMP '2022-08-19 09:00:00',
TIMESTAMP '2022-08-19 17:00:00' FROM DUAL UNION ALL
SELECT 'DOC6', TIMESTAMP '2022-08-20 09:00:00',
TIMESTAMP '2022-08-20 17:00:00' FROM DUAL UNION ALL
SELECT 'DOC7', TIMESTAMP '2022-08-21 09:00:00',
TIMESTAMP '2022-08-21 17:00:00' FROM DUAL;
SELECT
name,
StartDate,
EndDate,
datediff( 'hh', startdate, enddate)
FROM
TABLE_NAME
WHERE startdate between to_date( '01-AUG-2022 00:00:00', 'dd-mon-yyyy hh24:mi:ss' )
and to_date( '31-AUG-2022 23:59:59', 'dd-mon-yyyy hh24:mi:ss' )
AND
TO_CHAR(startdate, 'DY') NOT IN ('SAT', 'SUN');
ORDER BY 1,2
NAME STARTDATE ENDDATE DATEDIFF('HH',STARTDATE,ENDDATE)
DOC1 15-AUG-22 09.00.00.000000 AM 15-AUG-22 05.00.00.000000 PM 8
DOC2 16-AUG-22 09.00.00.000000 AM 16-AUG-22 05.00.00.000000 PM 8
DOC3 17-AUG-22 09.00.00.000000 AM 17-AUG-22 05.00.00.000000 PM 8
DOC4 18-AUG-22 09.00.00.000000 AM 18-AUG-22 05.00.00.000000 PM 8
DOC5 19-AUG-22 09.00.00.000000 AM 19-AUG-22 05.00.00.000000 PM

Time difference in correct format oracle

I want to difference between two time.
select
extract(hour from intrvl) as hh24,
extract(minute from intrvl) as mi
from
(select
to_timestamp_tz ('23:45','hh24:mi')
- to_timestamp_tz ('08:00','hh24:mi') as intrvl
from dual);
output-hh24-15
mi-45
Desired output:
hh24-08
mi-15
You can use a query like this
SELECT MOD (TRUNC (intrvl), 24) AS hours, (intrvl - TRUNC (intrvl)) * 60 AS minutes
FROM (SELECT 24 - ((TO_DATE ('23:45', 'hh24:mi') - TO_DATE ('08:00', 'hh24:mi')) * 24) AS intrvl
FROM DUAL);
If you want the part fo the day outside your time range - which is the only way I can see you'd get 08:15 - you can subtract your interval result from an interval of one day:
select
extract(hour from intrvl) as hh24,
extract(minute from intrvl) as mi
from (
select interval '1' day
- (to_timestamp_tz ('23:45','hh24:mi')
- to_timestamp_tz ('08:00','hh24:mi')) as intrvl
from dual
);
db<>fiddle

Time difference of hours and minutes [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I am trying to find out the time difference in hours and minutes but getting error, Please help to find out the query , For example I need answer of below in oracle
16:55- 14:00 = 2:55
Convert the times to a DATE or TIMESTAMP and then subtract one from the other to get an INTERVAL DAY TO SECOND data type; then use EXTRACT to get the hour and minute components and format them:
SELECT start_time,
end_time,
TO_CHAR( EXTRACT( HOUR FROM difference ), 'FM00' )
|| ':'
|| TO_CHAR( ABS( EXTRACT( MINUTE FROM DIFFERENCE ) ), 'FM00' )
AS difference
FROM (
SELECT start_time,
end_time,
( TO_DATE( end_time, 'HH24:MI' ) - TO_DATE( start_time, 'HH24:MI' ) ) DAY TO SECOND
AS difference
FROM test_data
)
Which, for the test data:
CREATE TABLE test_data ( start_time, end_time ) AS
SELECT '14:00', '16:55' FROM DUAL UNION ALL
SELECT '14:50', '15:23' FROM DUAL UNION ALL
SELECT '16:00', '14:00' FROM DUAL UNION ALL
SELECT '16:00', '14:20' FROM DUAL UNION ALL
SELECT '00:00', '23:59' FROM DUAL;
Outputs:
START_TIME | END_TIME | DIFFERENCE
:--------- | :------- | :---------
14:00 | 16:55 | 02:55
14:50 | 15:23 | 00:33
16:00 | 14:00 | -02:00
16:00 | 14:20 | -01:40
00:00 | 23:59 | 23:59
db<>fiddle here
Please see below
SELECT
substr(
to_char(TO_TIMESTAMP ('16:55', 'HH24:MI') -
TO_TIMESTAMP ('14:00', 'HH24:MI'),
'HH24:MI')
,12
,5) "Hours"
FROM
DUAL;
SELECT
to_number(substr(
to_char(TO_TIMESTAMP ('16:55', 'HH24:MI') -
TO_TIMESTAMP ('14:00', 'HH24:MI'),
'HH24:MI')
,12
,2))
+
to_number(substr(
to_char(TO_TIMESTAMP ('16:55', 'HH24:MI') -
TO_TIMESTAMP ('14:00', 'HH24:MI'),
'HH24:MI')
,15
,2))/60 "Decimal Hours"
FROM
DUAL;
Output
Hours
-----
02:55
Decimal Hours
-------------
2.91666667
Assuming that your two times are strings, you can use a query like the one below to calculate the difference between the times. By casting time strings to dates, you can then subtract them from each other and convert the result into the format that you want.
Query
WITH
times (start_time, end_time)
AS
(SELECT '14:00', '16:55' FROM DUAL
UNION ALL
SELECT '5:00', '3:00' FROM DUAL
UNION ALL
SELECT '7:00', '23:45' FROM DUAL
UNION ALL
SELECT '15:00', '03:20' FROM DUAL)
SELECT start_time,
end_time,
TRUNC (
( TO_DATE ('1-JAN-2000 ' || end_time, 'DD-MON-YYYY HH24:MI')
- TO_DATE ('1-JAN-2000 ' || start_time, 'DD-MON-YYYY HH24:MI'))
* 24)
|| ':'
|| RPAD (
ABS (
TRUNC (
( ( ( TO_DATE ('1-JAN-2000 ' || end_time, 'DD-MON-YYYY HH24:MI')
- TO_DATE ('1-JAN-2000 ' || start_time, 'DD-MON-YYYY HH24:MI'))
* 24)
- TRUNC (
( TO_DATE ('1-JAN-2000 ' || end_time, 'DD-MON-YYYY HH24:MI')
- TO_DATE ('1-JAN-2000 ' || start_time, 'DD-MON-YYYY HH24:MI'))
* 24))
* 60)),
2,
'0') AS difference
FROM times;
Result
START_TIME END_TIME DIFFERENCE
_____________ ___________ _____________
14:00 16:55 2:55
5:00 3:00 -2:00
7:00 23:45 16:45
15:00 03:20 -11:40

calculate the running total over the column contain date difference in HH:MI:SS format in oracle

I have to find the running total over the column interval.
SELECT
( ( EXTRACT(DAY FROM intrvl) * 24 ) + ( EXTRACT(HOUR FROM intrvl) ) ) ||':'||
EXTRACT(MINUTE FROM intrvl) ||':'||
EXTRACT(SECOND FROM intrvl) ||':'|| as interval
FROM
(
SELECT
( to_timestamp(TO_CHAR(date_column_name,'dd-mon-rrrr hh:mi:ss') ) ) - ( to_timestamp(TO_CHAR(date_column_name,'dd-mon-rrrr hh:mi:ss') ) ) intrvl
FROM
dual
);
currrently Interval column of table has below data:
Interval(HH:mi:ss)
0:4:23
696:1:36
696:4:51
8760:1:18
The best I can come up with is this. Note that the interval data type does not take a format model for displaying - you can't force an interval of 25 hours to be displayed as 25:00:00 (although you can use that to INPUT an interval). Instead, it will be shown as 01 01:00:00 (meaning, a day and an hour).
with
tbl (interv) as (
select interval '0:4:23' hour(9) to second from dual union all
select interval '696:1:36' hour(9) to second from dual union all
select interval '696:4:51' hour(9) to second from dual union all
select interval '8760:1:18' hour(9) to second from dual
)
select interval '1' day * sum(date '2000-01-01' + interv - date'2000-01-01')
as sum_interv
from tbl;
SUM_INTERV
--------------------
+423 00:12:08.000000
In your original attempt you were trying to get a STRING output. I am not sure that's wise, but if that's what you need you can do it like so:
with
tbl (interv) as (
select interval '0:4:23' hour(9) to second from dual union all
select interval '696:1:36' hour(9) to second from dual union all
select interval '696:4:51' hour(9) to second from dual union all
select interval '8760:1:18' hour(9) to second from dual
)
, prep (sum_interv) as (
select interval '1' day * sum(date '2000-01-01' + interv - date'2000-01-01')
from tbl
)
select to_char( extract(day from sum_interv) * 24
+ extract(hour from sum_interv), 'fm999999999' ) || ':' ||
to_char( extract(minute from sum_interv), 'fm00' ) || ':' ||
to_char( extract(second from sum_interv), 'fm00' ) as sum_interv
from prep
;
SUM_INTERV
------------------
10152:12:08

Want to round the data

My Query is :
SELECT TO_CHAR((to_date('01-01-2018 00:00:00','DD-MM-YYYY HH24:MI:SS')+ (level-1)),'DD-MM-YYYY'),
TO_CHAR(to_date('01-01-2018 00:00:00','DD-MM-YYYY HH24:MI:SS') + level,'DD-MM-YYYY') ,
to_number(regexp_substr('7000 T', '^\d+'))/(TO_DATE('04-01-2018 00:00:00', 'DD-MM-YYYY HH24:MI:SS') - TO_DATE('01-01-2018 00:00', 'DD-MM-YYYY HH24:MI:SS'))
|| regexp_substr('7000 T', '[A-Z]') AS IP_PLAN
FROM dual
CONNECT BY level <= to_date('04-01-2018 00:00:00','DD-MM-YYYY HH24:MI:SS')-to_date('01-01-2018 00:00:00','DD-MM-YYYY HH24:MI:SS');
I want IP_PLAN like: 2333 T
ROUND(('7000 T'), '[A-Z]') is trying to round a string value, i.e. the T that is extracted from that source string, which doesn't make sense.
You need to round the number you generated just before that:
select to_char(to_date('01-01-2018 00:00:00', 'DD-MM-YYYY HH24:MI:SS') + level - 1,
'DD-MM-YYYY'),
to_char(to_date('01-01-2018 00:00:00', 'DD-MM-YYYY HH24:MI:SS') + level,
'DD-MM-YYYY') ,
round(
to_number(regexp_substr('7000 T', '^[[:digit:]]+'))
/ (to_date('04-01-2018 00:00:00', 'DD-MM-YYYY HH24:MI:SS')
- to_date('01-01-2018 00:00', 'DD-MM-YYYY HH24:MI:SS'))
)
|| regexp_substr('7000 T', '[^[:digit:]]*$') as ip_plan_consumption
from dual
connect by level <= to_date('04-01-2018 00:00:00', 'DD-MM-YYYY HH24:MI:SS')
- to_date('01-01-2018 00:00:00', 'DD-MM-YYYY HH24:MI:SS');
TO_CHAR(TO TO_CHAR(TO IP_PLAN_CONSUMPTION
---------- ---------- ------------------------------------------
01-01-2018 02-01-2018 2333 T
02-01-2018 03-01-2018 2333 T
03-01-2018 04-01-2018 2333 T
so you're doing
round(<number extracted by regex> / <difference in days >)
which is
round(7000 / 3) => round(2333.333...) => 2333
and then appending the T after wards.
I've changed the regex patterns slightly so it picks up the space ans any characters at the end. That's making some assumptions about possible values in that string though - i.e. that it's always one number followed by one non-numeric section.
Incidentally, if you're using fixed dates then it's simpler to use date literals:
select to_char(date '2018-01-01' + level - 1, 'DD-MM-YYYY'),
to_char(date '2018-01-01' + level, 'DD-MM-YYYY') ,
round(
to_number(regexp_substr('7000 T', '^[[:digit:]]+'))
/ (date '2018-01-04' - date '2018-01-01')
)
|| regexp_substr('7000 T', '[^[:digit:]]*$') as ip_plan_consumption
from dual
connect by level <= date '2018-01-04' - date '2018-01-01';
though I imagine the 7000 T and the date values are all being passed in as string in your real code so they need to be converted. You could use a CTE to only convert them once though, instead of repeatedly as you loop round.
SELECT TO_CHAR((to_date('01-01-2018 00:00:00','DD-MM-YYYY HH24:MI:SS')+ (level-1)),'DD-MM-YYYY'),
TO_CHAR(to_date('01-01-2018 00:00:00','DD-MM-YYYY HH24:MI:SS') + level,'DD-MM-YYYY') ,
round(to_number(regexp_substr('7000 T', '^\d+'))/(TO_DATE('04-01-2018 00:00:00', 'DD-MM-YYYY HH24:MI:SS') - TO_DATE('01-01-2018 00:00', 'DD-MM-YYYY HH24:MI:SS')),0)
AS IP_PLAN_CONSUMPTION
FROM dual
CONNECT BY level <= to_date('04-01-2018 00:00:00','DD-MM-YYYY HH24:MI:SS')-to_date('01-01-2018 00:00:00','DD-MM-YYYY HH24:MI:SS');
you have to use T in some other column;

Resources