How to get hour and min from timestamp variable in Oracle SQL - sql

I got a timestamp variable like this:
INSERT INTO Table VALUES(TO_TIMESTAMP('2021-02-17 17:00','YYYY-MM-DD HH24:MI'));
I've created a trigger and my aim is to get the hour and min from that attribute so that I can compare them in two cursors like time.cur1 = time.cur2 (supposing that time is hour:min or hour+min), is there any cast like for the date,
CAST((timestamp) AS DATE)
should I create a new type after extracting the hour and min with
SELECT EXTRACT(HOUR FROM timestamp) FROM Table;
SELECT EXTRACT(MIN FROM timestamp) FROM Table;
or there is another way? (I'm using Oracle Database 11g). Thanks.

New type? No, put those values into a NUMBER datatype variables.
SQL> declare
2 l_hour number;
3 l_min number;
4 begin
5 select extract (hour from systimestamp),
6 extract (minute from systimestamp)
7 into l_hour,
8 l_min
9 from dual;
10
11 dbms_output.put_line('Hour: ' || l_hour ||'; minute: ' || l_min);
12 end;
13 /
Hour: 11; minute: 47
PL/SQL procedure successfully completed.
SQL>

SELECT TO_CHAR(SYSDATE, 'HH24') AS HOUR, TO_CHAR(SYSDATE, 'MI') AS MINUTS FROM DUAL;
TO YOUR EXAMPLE:
INSERT INTO Table VALUES(HOUR, MINUTS)
SELECT TO_CHAR(SYSDATE, 'HH24') AS HOUR, TO_CHAR(SYSDATE, 'MI') AS MINUTS;
FROM <EVERY_TABLE_OR_DUAL>;

Related

Insert records for 40years in table only date

I need to insert only date into a table MONTH_YEAR from 01-01-2010 to 01-01-2040:
For example, I need to insert record on my table month wise
DATE:
01-01-2010
01-02-2010
01-03-2010
01-04-2010
01-05-2010
01-06-2010
01-07-2010
01-08-2010
01-09-2010
01-10-2010
01-11-2010
01-12-2010
01-01-2011
01-02-2011
01-03-2011
01-04-2011
01-05-2011
.....................................
01-06-2040
01-07-2040
01-08-2040
01-09-2040
01-10-2040
01-11-2040
01-12-2040
Like this I want to insert only date into my table for month wise from 01-01-2010 to 01-01-2040
You can use a hierarchical query:
INSERT INTO month_year (column_name)
SELECT ADD_MONTHS(DATE '2010-01-01', LEVEL - 1)
FROM DUAL
CONNECT BY LEVEL <= 31*12;
Or a recursive query:
INSERT INTO month_year (column_name)
WITH range (dt) AS (
SELECT DATE '2010-01-01' FROM DUAL
UNION ALL
SELECT ADD_MONTHS(dt, 1)
FROM range
WHERE dt < DATE '2040-12-01'
)
SELECT dt FROM range;
db<>fiddle here
Row generator it is:
SQL> insert into month_year (datum)
2 select date '2010-01-01' + level - 1
3 from dual
4 connect by level <= date '2040-01-01' - date '2010-01-01' + 1;
10958 rows created.
SQL> select min(datum) min_date,
2 max(datum) max_date
3 from month_year;
MIN_DATE MAX_DATE
---------- ----------
01.01.2010 01.01.2040
SQL>
If you only need 1st of every month, then
SQL> insert into month_year (datum)
2 select add_months(date '2010-01-01', level - 1)
3 from dual
4 connect by level <= months_between(date '2040-01-01', date '2010-01-01') + 1;
361 rows created.
SQL>
Do you really need 40 years of dates, it seems unlikely or can you make due with a virtual calendar, where you specify a start and end_date and all the dates are generated for you. This example does every day in the range but feel free to modify it to produce what you need. I use it in several places.
CREATE OR REPLACE TYPE nt_date IS TABLE OF DATE;
CREATE OR REPLACE FUNCTION generate_dates_pipelined(
p_from IN DATE,
p_to IN DATE
)
RETURN nt_date PIPELINED DETERMINISTIC
IS
v_start DATE := TRUNC(LEAST(p_from, p_to));
v_end DATE := TRUNC(GREATEST(p_from, p_to));
BEGIN
LOOP
PIPE ROW (v_start);
EXIT WHEN v_start >= v_end;
v_start := v_start + INTERVAL '1' DAY;
END LOOP;
RETURN;
END generate_dates_pipelined;
/

SQL filter query output based on difference of two timestamp field [duplicate]

I have a table as follows:
Filename - varchar
Creation Date - Date format dd/mm/yyyy hh24:mi:ss
Oldest cdr date - Date format dd/mm/yyyy hh24:mi:ss
How can I calcuate the difference in hours minutes and seconds (and possibly days) between the two dates in Oracle SQL?
Thanks
You can substract dates in Oracle. This will give you the difference in days. Multiply by 24 to get hours, and so on.
SQL> select oldest - creation from my_table;
If your date is stored as character data, you have to convert it to a date type first.
SQL> select 24 * (to_date('2009-07-07 22:00', 'YYYY-MM-DD hh24:mi')
- to_date('2009-07-07 19:30', 'YYYY-MM-DD hh24:mi')) diff_hours
from dual;
DIFF_HOURS
----------
2.5
Note:
This answer applies to dates represented by the Oracle data type DATE.
Oracle also has a data type TIMESTAMP, which can also represent a date (with time). If you subtract TIMESTAMP values, you get an INTERVAL; to extract numeric values, use the EXTRACT function.
To get result in seconds:
select (END_DT - START_DT)*60*60*24 from MY_TABLE;
Check [https://community.oracle.com/thread/2145099?tstart=0][1]
select
extract( day from diff ) Days,
extract( hour from diff ) Hours,
extract( minute from diff ) Minutes
from (
select (CAST(creationdate as timestamp) - CAST(oldcreationdate as timestamp)) diff
from [TableName]
);
This will give you three columns as Days, Hours and Minutes.
declare
strTime1 varchar2(50) := '02/08/2013 01:09:42 PM';
strTime2 varchar2(50) := '02/08/2013 11:09:00 PM';
v_date1 date := to_date(strTime1,'DD/MM/YYYY HH:MI:SS PM');
v_date2 date := to_date(strTime2,'DD/MM/YYYY HH:MI:SS PM');
difrence_In_Hours number;
difrence_In_minutes number;
difrence_In_seconds number;
begin
difrence_In_Hours := (v_date2 - v_date1) * 24;
difrence_In_minutes := difrence_In_Hours * 60;
difrence_In_seconds := difrence_In_minutes * 60;
dbms_output.put_line(strTime1);
dbms_output.put_line(strTime2);
dbms_output.put_line('*******');
dbms_output.put_line('difrence_In_Hours : ' || difrence_In_Hours);
dbms_output.put_line('difrence_In_minutes: ' || difrence_In_minutes);
dbms_output.put_line('difrence_In_seconds: ' || difrence_In_seconds);
end ;
Hope this helps.
You may also try this:
select to_char(to_date('1970-01-01 00:00:00', 'yyyy-mm-dd hh24:mi:ss')+(end_date - start_date),'hh24:mi:ss')
as run_time from some_table;
It displays time in more human readable form, like: 00:01:34.
If you need also days you may simply add DD to last formatting string.
Calculate age from HIREDATE to system date of your computer
SELECT HIREDATE||' '||SYSDATE||' ' ||
TRUNC(MONTHS_BETWEEN(SYSDATE,HIREDATE)/12) ||' YEARS '||
TRUNC((MONTHS_BETWEEN(SYSDATE,HIREDATE))-(TRUNC(MONTHS_BETWEEN(SYSDATE,HIREDATE)/12)*12))||
'MONTHS' AS "AGE " FROM EMP;
You could use to_timestamp function to convert the dates to timestamps and perform a substract operation.
Something like:
SELECT
TO_TIMESTAMP ('13.10.1990 00:00:00','DD.MM.YYYY HH24:MI:SS') -
TO_TIMESTAMP ('01.01.1990:00:10:00','DD.MM.YYYY:HH24:MI:SS')
FROM DUAL
In oracle 11g
SELECT end_date - start_date AS day_diff FROM tablexxx
suppose the starT_date end_date is define in the tablexxx
select days||' '|| time from (
SELECT to_number( to_char(to_date('1','J') +
(CLOSED_DATE - CREATED_DATE), 'J') - 1) days,
to_char(to_date('00:00:00','HH24:MI:SS') +
(CLOSED_DATE - CREATED_DATE), 'HH24:MI:SS') time
FROM request where REQUEST_ID=158761088 );
If you want something that looks a bit simpler, try this for finding events in a table which occurred in the past 1 minute:
With this entry you can fiddle with the decimal values till you get the minute value that you want. The value .0007 happens to be 1 minute as far as the sysdate significant digits are concerned. You can use multiples of that to get any other value that you want:
select (sysdate - (sysdate - .0007)) * 1440 from dual;
Result is 1 (minute)
Then it is a simple matter to check for
select * from my_table where (sysdate - transdate) < .00071;
If you select two dates from 'your_table' and want too see the result as a single column output (eg. 'days - hh:mm:ss') you could use something like this.
First you could calculate the interval between these two dates and after that export all the data you need from that interval:
select extract (day from numtodsinterval (second_date
- add_months (created_date,
floor (months_between (second_date,created_date))),
'day'))
|| ' days - '
|| extract (hour from numtodsinterval (second_date
- add_months (created_date,
floor (months_between (second_date,created_date))),
'day'))
|| ':'
|| extract (minute from numtodsinterval (second_date
- add_months (created_date,
floor (months_between (second_date, created_date))),
'day'))
|| ':'
|| extract (second from numtodsinterval (second_date
- add_months (created_date,
floor (months_between (second_date, created_date))),
'day'))
from your_table
And that should give you result like this:
0 days - 1:14:55
select (floor(((DATE2-DATE1)*24*60*60)/3600)|| ' : ' ||floor((((DATE2-DATE1)*24*60*60) -floor(((DATE2-DATE1)*24*60*60)/3600)*3600)/60)|| ' ' ) as time_difference from TABLE1
(TO_DATE(:P_comapre_date_1, 'dd-mm-yyyy hh24:mi') - TO_DATE(:P_comapre_date_2, 'dd-mm-yyyy hh24:mi'))*60*60*24 sum_seconds,
(TO_DATE(:P_comapre_date_1, 'dd-mm-yyyy hh24:mi') - TO_DATE(:P_comapre_date_2, 'dd-mm-yyyy hh24:mi'))*60*24 sum_minutes,
(TO_DATE(:P_comapre_date_1, 'dd-mm-yyyy hh24:mi') - TO_DATE(:P_comapre_date_2, 'dd-mm-yyyy hh24:mi'))*24 sum_hours,
(TO_DATE(:P_comapre_date_1, 'dd-mm-yyyy hh24:mi') - TO_DATE(:P_comapre_date_2, 'dd-mm-yyyy hh24:mi')) sum_days
select to_char(actual_start_date,'DD-MON-YYYY hh24:mi:ss') start_time,
to_char(actual_completion_date,'DD-MON-YYYY hh24:mi:ss') end_time,
floor((actual_completion_date-actual_start_date)*24*60)||'.'||round(mod((actual_completion_date-actual_start_date)*24*60*60,60)) diff_time
from fnd_concurrent_requests
order by request_id desc;
If You want get date defer from using table and column.
SELECT TO_DATE( TO_CHAR(COLUMN_NAME_1, 'YYYY-MM-DD'), 'YYYY-MM-DD') -
TO_DATE(TO_CHAR(COLUMN_NAME_2, 'YYYY-MM-DD') , 'YYYY-MM-DD') AS DATEDIFF
FROM TABLE_NAME;
This will count time between to dates:
SELECT
(TO_CHAR( TRUNC (ROUND(((sysdate+1) - sysdate)*24,2))*60,'999999')
+
TO_CHAR(((((sysdate+1)-sysdate)*24)- TRUNC(ROUND(((sysdate+1) - sysdate)*24,2)))/100*60 *100, '09'))/60
FROM dual
Here's another option:
with tbl_demo AS
(SELECT TO_DATE('11/26/2013 13:18:50', 'MM/DD/YYYY HH24:MI:SS') dt1
, TO_DATE('11/28/2013 21:59:12', 'MM/DD/YYYY HH24:MI:SS') dt2
FROM dual)
SELECT dt1
, dt2
, round(dt2 - dt1,2) diff_days
, round(dt2 - dt1,2)*24 diff_hrs
, numtodsinterval((dt2 - dt1),'day') diff_dd_hh_mm_ss
from tbl_demo;
Single query that will return time difference of two timestamp columns:
select INS_TS, MAIL_SENT_TS, extract( hour from (INS_TS - MAIL_SENT_TS) ) timeDiff
from MAIL_NOTIFICATIONS;
select round( (tbl.Todate - tbl.fromDate) * 24 * 60 * 60 )
from table tbl
for oracle sql I justbn did this and works perfect :
SELECT trunc(date_col_1) - trunc(date_col_2)
FROM TABLE;
$sql="select bsp_bp,user_name,status,
to_char(ins_date,'dd/mm/yyyy hh12:mi:ss AM'),
to_char(pickup_date,'dd/mm/yyyy hh12:mi:ss AM'),
trunc((pickup_date-ins_date)*24*60*60,2),message,status_message
from valid_bsp_req where id >= '$id'";

Subtracting the difference between two time intervals in oracle sql [duplicate]

I have a table as follows:
Filename - varchar
Creation Date - Date format dd/mm/yyyy hh24:mi:ss
Oldest cdr date - Date format dd/mm/yyyy hh24:mi:ss
How can I calcuate the difference in hours minutes and seconds (and possibly days) between the two dates in Oracle SQL?
Thanks
You can substract dates in Oracle. This will give you the difference in days. Multiply by 24 to get hours, and so on.
SQL> select oldest - creation from my_table;
If your date is stored as character data, you have to convert it to a date type first.
SQL> select 24 * (to_date('2009-07-07 22:00', 'YYYY-MM-DD hh24:mi')
- to_date('2009-07-07 19:30', 'YYYY-MM-DD hh24:mi')) diff_hours
from dual;
DIFF_HOURS
----------
2.5
Note:
This answer applies to dates represented by the Oracle data type DATE.
Oracle also has a data type TIMESTAMP, which can also represent a date (with time). If you subtract TIMESTAMP values, you get an INTERVAL; to extract numeric values, use the EXTRACT function.
To get result in seconds:
select (END_DT - START_DT)*60*60*24 from MY_TABLE;
Check [https://community.oracle.com/thread/2145099?tstart=0][1]
select
extract( day from diff ) Days,
extract( hour from diff ) Hours,
extract( minute from diff ) Minutes
from (
select (CAST(creationdate as timestamp) - CAST(oldcreationdate as timestamp)) diff
from [TableName]
);
This will give you three columns as Days, Hours and Minutes.
declare
strTime1 varchar2(50) := '02/08/2013 01:09:42 PM';
strTime2 varchar2(50) := '02/08/2013 11:09:00 PM';
v_date1 date := to_date(strTime1,'DD/MM/YYYY HH:MI:SS PM');
v_date2 date := to_date(strTime2,'DD/MM/YYYY HH:MI:SS PM');
difrence_In_Hours number;
difrence_In_minutes number;
difrence_In_seconds number;
begin
difrence_In_Hours := (v_date2 - v_date1) * 24;
difrence_In_minutes := difrence_In_Hours * 60;
difrence_In_seconds := difrence_In_minutes * 60;
dbms_output.put_line(strTime1);
dbms_output.put_line(strTime2);
dbms_output.put_line('*******');
dbms_output.put_line('difrence_In_Hours : ' || difrence_In_Hours);
dbms_output.put_line('difrence_In_minutes: ' || difrence_In_minutes);
dbms_output.put_line('difrence_In_seconds: ' || difrence_In_seconds);
end ;
Hope this helps.
You may also try this:
select to_char(to_date('1970-01-01 00:00:00', 'yyyy-mm-dd hh24:mi:ss')+(end_date - start_date),'hh24:mi:ss')
as run_time from some_table;
It displays time in more human readable form, like: 00:01:34.
If you need also days you may simply add DD to last formatting string.
Calculate age from HIREDATE to system date of your computer
SELECT HIREDATE||' '||SYSDATE||' ' ||
TRUNC(MONTHS_BETWEEN(SYSDATE,HIREDATE)/12) ||' YEARS '||
TRUNC((MONTHS_BETWEEN(SYSDATE,HIREDATE))-(TRUNC(MONTHS_BETWEEN(SYSDATE,HIREDATE)/12)*12))||
'MONTHS' AS "AGE " FROM EMP;
You could use to_timestamp function to convert the dates to timestamps and perform a substract operation.
Something like:
SELECT
TO_TIMESTAMP ('13.10.1990 00:00:00','DD.MM.YYYY HH24:MI:SS') -
TO_TIMESTAMP ('01.01.1990:00:10:00','DD.MM.YYYY:HH24:MI:SS')
FROM DUAL
In oracle 11g
SELECT end_date - start_date AS day_diff FROM tablexxx
suppose the starT_date end_date is define in the tablexxx
select days||' '|| time from (
SELECT to_number( to_char(to_date('1','J') +
(CLOSED_DATE - CREATED_DATE), 'J') - 1) days,
to_char(to_date('00:00:00','HH24:MI:SS') +
(CLOSED_DATE - CREATED_DATE), 'HH24:MI:SS') time
FROM request where REQUEST_ID=158761088 );
If you want something that looks a bit simpler, try this for finding events in a table which occurred in the past 1 minute:
With this entry you can fiddle with the decimal values till you get the minute value that you want. The value .0007 happens to be 1 minute as far as the sysdate significant digits are concerned. You can use multiples of that to get any other value that you want:
select (sysdate - (sysdate - .0007)) * 1440 from dual;
Result is 1 (minute)
Then it is a simple matter to check for
select * from my_table where (sysdate - transdate) < .00071;
If you select two dates from 'your_table' and want too see the result as a single column output (eg. 'days - hh:mm:ss') you could use something like this.
First you could calculate the interval between these two dates and after that export all the data you need from that interval:
select extract (day from numtodsinterval (second_date
- add_months (created_date,
floor (months_between (second_date,created_date))),
'day'))
|| ' days - '
|| extract (hour from numtodsinterval (second_date
- add_months (created_date,
floor (months_between (second_date,created_date))),
'day'))
|| ':'
|| extract (minute from numtodsinterval (second_date
- add_months (created_date,
floor (months_between (second_date, created_date))),
'day'))
|| ':'
|| extract (second from numtodsinterval (second_date
- add_months (created_date,
floor (months_between (second_date, created_date))),
'day'))
from your_table
And that should give you result like this:
0 days - 1:14:55
select (floor(((DATE2-DATE1)*24*60*60)/3600)|| ' : ' ||floor((((DATE2-DATE1)*24*60*60) -floor(((DATE2-DATE1)*24*60*60)/3600)*3600)/60)|| ' ' ) as time_difference from TABLE1
(TO_DATE(:P_comapre_date_1, 'dd-mm-yyyy hh24:mi') - TO_DATE(:P_comapre_date_2, 'dd-mm-yyyy hh24:mi'))*60*60*24 sum_seconds,
(TO_DATE(:P_comapre_date_1, 'dd-mm-yyyy hh24:mi') - TO_DATE(:P_comapre_date_2, 'dd-mm-yyyy hh24:mi'))*60*24 sum_minutes,
(TO_DATE(:P_comapre_date_1, 'dd-mm-yyyy hh24:mi') - TO_DATE(:P_comapre_date_2, 'dd-mm-yyyy hh24:mi'))*24 sum_hours,
(TO_DATE(:P_comapre_date_1, 'dd-mm-yyyy hh24:mi') - TO_DATE(:P_comapre_date_2, 'dd-mm-yyyy hh24:mi')) sum_days
select to_char(actual_start_date,'DD-MON-YYYY hh24:mi:ss') start_time,
to_char(actual_completion_date,'DD-MON-YYYY hh24:mi:ss') end_time,
floor((actual_completion_date-actual_start_date)*24*60)||'.'||round(mod((actual_completion_date-actual_start_date)*24*60*60,60)) diff_time
from fnd_concurrent_requests
order by request_id desc;
If You want get date defer from using table and column.
SELECT TO_DATE( TO_CHAR(COLUMN_NAME_1, 'YYYY-MM-DD'), 'YYYY-MM-DD') -
TO_DATE(TO_CHAR(COLUMN_NAME_2, 'YYYY-MM-DD') , 'YYYY-MM-DD') AS DATEDIFF
FROM TABLE_NAME;
This will count time between to dates:
SELECT
(TO_CHAR( TRUNC (ROUND(((sysdate+1) - sysdate)*24,2))*60,'999999')
+
TO_CHAR(((((sysdate+1)-sysdate)*24)- TRUNC(ROUND(((sysdate+1) - sysdate)*24,2)))/100*60 *100, '09'))/60
FROM dual
Here's another option:
with tbl_demo AS
(SELECT TO_DATE('11/26/2013 13:18:50', 'MM/DD/YYYY HH24:MI:SS') dt1
, TO_DATE('11/28/2013 21:59:12', 'MM/DD/YYYY HH24:MI:SS') dt2
FROM dual)
SELECT dt1
, dt2
, round(dt2 - dt1,2) diff_days
, round(dt2 - dt1,2)*24 diff_hrs
, numtodsinterval((dt2 - dt1),'day') diff_dd_hh_mm_ss
from tbl_demo;
Single query that will return time difference of two timestamp columns:
select INS_TS, MAIL_SENT_TS, extract( hour from (INS_TS - MAIL_SENT_TS) ) timeDiff
from MAIL_NOTIFICATIONS;
select round( (tbl.Todate - tbl.fromDate) * 24 * 60 * 60 )
from table tbl
for oracle sql I justbn did this and works perfect :
SELECT trunc(date_col_1) - trunc(date_col_2)
FROM TABLE;
$sql="select bsp_bp,user_name,status,
to_char(ins_date,'dd/mm/yyyy hh12:mi:ss AM'),
to_char(pickup_date,'dd/mm/yyyy hh12:mi:ss AM'),
trunc((pickup_date-ins_date)*24*60*60,2),message,status_message
from valid_bsp_req where id >= '$id'";

Oracle Convert Seconds to Hours:Minutes:Seconds

I have a requirement to display user available time in Hours:Minutes:Seconds format from a given total number of seconds value. Appreciate if you know a ORACLE function to do the same. I'm using Oracle.
Thank you for your time.
If you're just looking to convert a given number of seconds into HH:MI:SS format, this should do it
SELECT
TO_CHAR(TRUNC(x/3600),'FM9900') || ':' ||
TO_CHAR(TRUNC(MOD(x,3600)/60),'FM00') || ':' ||
TO_CHAR(MOD(x,60),'FM00')
FROM DUAL
where x is the number of seconds.
Try this one.
Very simple and easy to use
select to_char(to_date(10000,'sssss'),'hh24:mi:ss') from dual;
The following code is less complex and gives the same result. Note that 'X' is the number of seconds to be converted to hours.
In Oracle use:
SELECT TO_CHAR (TRUNC (SYSDATE) + NUMTODSINTERVAL (X, 'second'),
'hh24:mi:ss'
) hr
FROM DUAL;
In SqlServer use:
SELECT CONVERT(varchar, DATEADD(s, X, 0), 108);
If you have a variable containing f.e. 1 minute(in seconds), you can add it to the systimestamp then use to_char to select the different time parts from it.
select to_char(systimestamp+60/(24*60*60), 'yyyy.mm.dd HH24:mi:ss') from dual
For the comment on the answer by vogash, I understand that you want something like a time counter, thats because you can have more than 24 hours. For this you can do the following:
select to_char(trunc(xxx/3600)) || to_char(to_date(mod(xxx, 86400),'sssss'),':mi:ss') as time
from dual;
xxx are your number of seconds.
The first part accumulate the hours and the second part calculates the remaining minutes and seconds. For example, having 150023 seconds it will give you 41:40:23.
But if you always want have hh24:mi:ss even if you have more than 86000 seconds (1 day) you can do:
select to_char(to_date(mod(xxx, 86400),'sssss'),'hh24:mi:ss') as time
from dual;
xxx are your number of seconds.
For example, having 86402 seconds it will reset the time to 00:00:02.
Unfortunately not... However, there's a simple trick if it's going to be less than 24 hours.
Oracle assumes that a number added to a date is in days. Convert the number of seconds into days. Add the current day, then use the to_date function to take only the parts your interested in. Assuming you have x seconds:
select to_char(sysdate + (x / ( 60 * 60 * 24 ) ), 'HH24:MI:SS')
from dual
This won't work if there's more than 24 hours, though you can remove the current data again and get the difference in days, hours, minutes and seconds.
If you want something like: 51:10:05, i.e. 51 hours, 10 minutes and 5 seconds then you're going to have to use trunc.
Once again assuming that you have x seconds...
The number of hours is trunc(x / 60 / 60)
The number of minutes is trunc((x - ( trunc(x / 60 / 60) * 60 * 60 )) / 60)
The number of seconds is therefore the x - hours * 60 * 60 - minutes * 60
Leaving you with:
with hrs as (
select x, trunc(x / 60 / 60) as h
from dual
)
, mins as (
select x, h, trunc((x - h * 60 * 60) / 60) as m
from hrs
)
select h, m, x - (h * 60 * 60) - (m * 60)
from mins
I've set up a SQL Fiddle to demonstrate.
The following is Yet Another Way (tm) - still involves a little calculation but provides an example of using EXTRACT to pull the individual fields out of an INTERVAL:
DECLARE
SUBTYPE BIG_INTERVAL IS INTERVAL DAY(9) TO SECOND;
i BIG_INTERVAL;
nSeconds NUMBER := 86400000;
FUNCTION INTERVAL_TO_HMS_STRING(inv IN BIG_INTERVAL)
RETURN VARCHAR2
IS
nHours NUMBER;
nMinutes NUMBER;
nSeconds NUMBER;
strHour_format VARCHAR2(10) := '09';
workInv INTERVAL DAY(9) TO SECOND(9);
BEGIN
nHours := EXTRACT(HOUR FROM inv) + (EXTRACT(DAY FROM inv) * 24);
strHour_format := TRIM(RPAD(' ', LENGTH(TRIM(TO_CHAR(ABS(nHours)))), '0') || '9');
nMinutes := ABS(EXTRACT(MINUTE FROM inv));
nSeconds := ABS(EXTRACT(SECOND FROM inv));
RETURN TRIM(TO_CHAR(nHours, strHour_format)) || ':' ||
TRIM(TO_CHAR(nMInutes, '09')) || ':' ||
TRIM(TO_CHAR(nSeconds, '09'));
END INTERVAL_TO_HMS_STRING;
BEGIN
i := NUMTODSINTERVAL(nSeconds, 'SECOND');
DBMS_OUTPUT.PUT_LINE('i (fields) = ' || INTERVAL_TO_HMS_STRING(i));
END;
The code which extracts the fields, etc, still has to contain a calculation to convert the DAY field to equivalent hours, and is not the prettiest, but wrapped up neatly in a procedure it's not too bad to use.
Share and enjoy.
Assuming your time is called st.etime below and stored in seconds, here is what I use. This handles times where the seconds are greater than 86399 seconds (which is 11:59:59 pm)
case when st.etime > 86399 then to_char(to_date(st.etime - 86400,'sssss'),'HH24:MI:SS') else to_char(to_date(st.etime,'sssss'),'HH24:MI:SS') end readable_time
My version. Show Oracle DB uptime in format DDd HHh MMm SSs
select to_char(trunc((((86400*x)/60)/60)/24)) || 'd ' ||
to_char(trunc(((86400*x)/60)/60)-24*(trunc((((86400*x)/60)/60)/24)), 'FM00') || 'h ' ||
to_char(trunc((86400*x)/60)-60*(trunc(((86400*x)/60)/60)), 'FM00') || 'm ' ||
to_char(trunc(86400*x)-60*(trunc((86400*x)/60)), 'FM00') || 's' "UPTIME"
from (select (sysdate - t.startup_time) x from V$INSTANCE t);
idea from Date / Time Arithmetic with Oracle 9/10
Convert minutes to hour:min:sec format
SELECT
TO_CHAR(TRUNC((MINUTES * 60) / 3600), 'FM9900') || ':' ||
TO_CHAR(TRUNC(MOD((MINUTES * 60), 3600) / 60), 'FM00') || ':' ||
TO_CHAR(MOD((MINUTES * 60), 60), 'FM00') AS MIN_TO_HOUR FROM DUAL
For greater than 24 hours you can include days with the following query. The returned format is days:hh24:mi:ss
Query:
select trunc(trunc(sysdate) + numtodsinterval(9999999, 'second')) - trunc(sysdate) || ':' || to_char(trunc(sysdate) + numtodsinterval(9999999, 'second'), 'hh24:mi:ss') from dual;
Output:
115:17:46:39
create or replace procedure mili(num in number)
as
yr number;
yrsms number;
mon number;
monsms number;
wk number;
wksms number;
dy number;
dysms number;
hr number;
hrsms number;
mn number;
mnsms number;
sec number;
begin
yr := FLOOR(num/31556952000);
yrsms := mod(num, 31556952000);
mon := FLOOR(yrsms/2629746000);
monsms := mod(num,2629746000);
wk := FLOOR(monsms/(604800000));
wksms := mod(num,604800000);
dy := floor(wksms/ (24*60*60*1000));
dysms :=mod(num,24*60*60*1000);
hr := floor((dysms)/(60*60*1000));
hrsms := mod(num,60*60*1000);
mn := floor((hrsms)/(60*1000));
mnsms := mod(num,60*1000);
sec := floor((mnsms)/(1000));
dbms_output.put_line(' Year:'||yr||' Month:'||mon||' Week:'||wk||' Day:'||dy||' Hour:'||hr||' Min:'||mn||' Sec: '||sec);
end;
/
begin
mili(12345678904234);
end;
create or replace function `seconds_hh_mi_ss` (seconds in number)
return varchar2
is
hours_var number;
minutes_var number;
seconds_var number;
remeinder_var number;
output_var varchar2(32);
begin
select seconds - mod(seconds,3600) into hours_var from dual;
select seconds - hours_var into remeinder_var from dual;
select (remeinder_var - mod(remeinder_var,60)) into minutes_var from dual;
select seconds - (hours_var+minutes_var) into seconds_var from dual;
output_var := hours_var/3600||':'||minutes_var/60||':'||seconds_var;
return(output_var);
end;
/
You should check out this site. The TO_TIMESTAMP section could be useful for you!
Syntax:
TO_TIMESTAMP ( string , [ format_mask ] [ 'nlsparam' ] )

Difference between two dates

I have a table that has the following data
fromDate | toDate
20JAN11 | 29DEC30
Both dates are for the 21st Century (i.e. 2011 and 2030) but only the last two characters are stored.
Why is the following statement (when run from within a PL/SQL module) against the above data always returns a positive value
dateDifference := (fromDate - toDate)
If i run the following statement from sqlplus i get the correct negative value which is correct.
select to_date('20JAN11','DDMONYY')-to_Date('29DEC30','DDMONYY') from dual;
I remember reading somewhere that Oracle would sometimes use the wrong century but i dont quite remember the exact scenario where that would happen.
Assuming those columns are of DATE datatype, which seems to be the case: Oracle always stores DATE values in an internal format which includes the full year. The fact that you are seeing only a 2-digit year has to do with the date format used to convert the date to a string for display. So most likely the stored century values are not what you think they are.
Try selecting the dates with an explicit format to see what you really have stored:
SELECT TO_CHAR( fromDate, 'DD-MON-YYYY' ), TO_CHAR( toDate, 'DD-MON-YYYY' )
Seems to work for me either way on my 10g database:
SQL> set serveroutput on
SQL>
SQL> DECLARE
2 d1 DATE := to_date('20JAN11','DDMONRR');
3 d2 DATE := to_date('29DEC30','DDMONRR');
4 diff INTEGER;
5 BEGIN
6 diff := d1 - d2;
7 dbms_output.put_line(diff);
8 END;
9 /
-7283
PL/SQL procedure successfully completed
SQL>
EDIT: works for YY instead of RR year format as well.
EDIT2: Something like this, you mean?
SQL> create table t (d1 date, d2 date);
Table created
SQL> insert into t values (to_date('20JAN11','DDMONYY'), to_date('29DEC30','DDMONYY'));
1 row inserted
SQL> commit;
Commit complete
SQL>
SQL> DECLARE
2 R t%ROWTYPE;
3 diff INTEGER;
4 BEGIN
5 SELECT d1, d2
6 INTO R
7 FROM t;
8 diff := R.d1 - R.d2;
9 dbms_output.put_line(diff);
10 END;
11 /
-7283
PL/SQL procedure successfully completed
SQL>
As #Alex states, you may want to verify your data.
works without formatting as well
CREATE TABLE DATETEST(FROMDATE DATE, TODATE DATE);
insert into DATETEST (fromdate,todate) values (to_date('20Jan11','ddMonrr'),to_date('29DEC30','ddMonrr'));
SELECT TO_CHAR(FROMDATE,'ddMonrrrr hh24:mi:ss') FROMDATE,
TO_CHAR(TODATE,'ddMonrrrr hh24:mi:ss') TODATE
from datetest ;
/*
FROMDATE TODATE
------------------ ------------------
20Jan2011 00:00:00 29Dec2030 00:00:00
*/
set serveroutput on
DECLARE
l_FROMDATE DATETEST.FROMDATE%type ;
L_TODATE DATETEST.TODATE%TYPE;
dateDifference number;
BEGIN
--notice -- no formatting just putting them into a variable for test
SELECT FROMDATE, TODATE
INTO L_FROMDATE, L_TODATE
from datetest;
DATEDIFFERENCE := L_FROMDATE - L_TODATE ;
DBMS_OUTPUT.PUT_LINE('DATEDIFFERENCE = ' || DATEDIFFERENCE );
end ;
--DATEDIFFERENCE = -7283
SELECT FROMDATE-TODATE
from datetest ;
/* --still not formatting
FROMDATE-TODATE
----------------------
-7283
*/
SELECT (FROMDATE - TODATE) DATEDIFF,
TO_CHAR(FROMDATE,'ddMonrrrr') FROMDATE,
to_char(todate,'ddMonrrrr') todate
from (
SELECT TO_DATE('20JAN11','DDMONYY') FROMDATE,
TO_DATE('29DEC30','DDMONYY') TODATE
FROM DUAL)
;
/*
DATEDIFF FROMDATE TODATE
---------------------- --------- ---------
-7283 20Jan2011 29Dec2030
*/
try running the first query on your table:
SELECT TO_CHAR(FROMDATE,'ddMonrrrr hh24:mi:ss') FROMDATE,
TO_CHAR(TODATE,'ddMonrrrr hh24:mi:ss') TODATE
from datetest ;
see if the years are what you actually expect.
(Edit: changed to use two digit years)