Time difference in correct format oracle - 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

Related

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

Oracle adding randim amount if seconds to a date

I have a date that is always set to midnight i.e. '07312021 00:00:00' how can I use dbms_random.value to add (1 second, 23:59:59) to that date.
SELECT DATE '2021-07-31' + INTERVAL '1' SECOND * FLOOR(DBMS_RANDOM.VALUE(0, 86400))
FROM DUAL;
Or
SELECT DATE '2021-07-31' + NUMTODSINTERVAL(
FLOOR(DBMS_RANDOM.VALUE(0, 86400)),
'SECOND'
)
FROM DUAL;
Or
SELECT DATE '2021-07-31' + DBMS_RANDOM.VALUE
FROM DUAL;
sqlfiddle here

oracle convert unix epoch time to date

The context is that there is an existing application in our product which generates and sends the EPOCH number to an existing oracle procedure & vice versa. It works in that procedure using something like this
SELECT UTC_TO_DATE (1463533832) FROM DUAL
SELECT date_to_utc(creation_date) FROM mytable
When I tried these queries it does work for me as well with Oracle 10g server (and oracle sql developer 4.x if that matters).
In the existing procedure the requirement was to save the value as date itself (time component was irrelevant), however in the new requirement I have to convert unix EPOCH value to datetime (at the hours/mins/seconds level, or better in a specific format such as dd-MMM-yyyy hh:mm:ss) in an oracle query. Strangely I am unable to find any documentation around the UTC_TO_DATE and DATE_TO_UTC functions with Google. I have looked around at all different questions on stackoverflow, but most of them are specific to programming languages such as php, java etc.
Bottom line, how to convert EPOCH to that level of time using these functions (or any other functions) in Oracle query? Additionally are those functions I am referring could be custom or specific somewhere, as I don't see any documentation or reference to this.
To convert from milliseconds from epoch (assume epoch is Jan 1st 1970):
select to_date('19700101', 'YYYYMMDD') + ( 1 / 24 / 60 / 60 / 1000) * 1322629200000
from dual;
11/30/2011 5:00:00 AM
To convert that date back to milliseconds:
select (to_date('11/30/2011 05:00:00', 'MM/DD/YYYY HH24:MI:SS') - to_date('19700101', 'YYYYMMDD')) * 24 * 60 * 60 * 1000
from dual;
1322629200000
If its seconds instead of milliseconds, just omit the 1000 part of the equation:
select to_date('19700101', 'YYYYMMDD') + ( 1 / 24 / 60 / 60 ) * 1322629200
from dual;
select (to_date('11/30/2011 05:00:00', 'MM/DD/YYYY HH24:MI:SS') - to_date('19700101', 'YYYYMMDD')) * 24 * 60 * 60
from dual;
Hope that helps.
Another option is to use an interval type:
SELECT TO_TIMESTAMP('1970-01-01 00:00:00.0'
,'YYYY-MM-DD HH24:MI:SS.FF'
) + NUMTODSINTERVAL(1493963084212/1000, 'SECOND')
FROM dual;
It has this advantage that milliseconds won't be cut.
If your epoch time is stored as an integer.....
And you desire the conversion to Oracle date format.
Step 1-->
Add your epoch date (1462086000) to standard 01-jan-1970. 86400 is seconds in a 24 hour period.
*Select TO_DATE('01-jan-1970', 'dd-mon-yyyy') + 1462086000/86400 from dual*
**output is 5/1/2016 7:00:00 AM**
Step 2--> Convert it to a CHAR . This is needed for formatting before additional functions can be applied.
*Select TO_CHAR(TO_DATE('01-jan-1970', 'dd-mon-yyyy') + 1462086000/86400 ,'yyyy-mm-dd hh24:mi:ss') from dual*
output is 2016-05-01 07:00:00
Step 3--> Now onto Timestamp conversion
Select to_timestamp(TO_CHAR(TO_DATE('01-jan-1970', 'dd-mon-yyyy') + 1462086000/86400 ,'yyyy-mm-dd hh24:mi:ss'), 'yyyy-mm-dd hh24:mi:ss') from dual
output is 5/1/2016 7:00:00.000000000 AM
Step 4--> Now need the TimeZone, usage of UTC
Select from_tz(to_timestamp(TO_CHAR(TO_DATE('01-jan-1970', 'dd-mon-yyyy') + 1462086000/86400 ,'yyyy-mm-dd hh24:mi:ss'), 'yyyy-mm-dd hh24:mi:ss'),'UTC') from dual
output is 5/1/2016 7:00:00.000000000 AM +00:00
Step 5--> If your timezone need is PST
Select from_tz(to_timestamp(TO_CHAR(TO_DATE('01-jan-1970', 'dd-mon-yyyy') + 1462086000/86400 ,'yyyy-mm-dd hh24:mi:ss'), 'yyyy-mm-dd hh24:mi:ss'),'UTC') at time zone 'America/Los_Angeles' TZ from dual
output is 5/1/2016 12:00:00.000000000 AM -07:00
Step 6--> Format the PST Timezone timestamp.
Select to_Char(from_tz(to_timestamp(TO_CHAR(TO_DATE('01-jan-1970', 'dd-mon-yyyy') + 1462086000/86400 ,'yyyy-mm-dd hh24:mi:ss'), 'yyyy-mm-dd hh24:mi:ss'),'UTC') at time zone 'America/Los_Angeles' ,'DD-MON-YYYY HH24:MI:SS') TZ from dual
output is 01-MAY-2016 00:00:00
Step 7--> And finally, if your column is date datatype
Add to_DATE to the whole above Select.
Here it is for both UTC/GMT and EST;
GMT select (to_date('1970-01-01 00','yyyy-mm-dd hh24') +
(1519232926891)/1000/60/60/24) from dual;
EST select new_time(to_date('1970-01-01 00','yyyy-mm-dd hh24') +
(1519232926891)/1000/60/60/24, 'GMT', 'EST') from dual;
I thought somebody would be interested in seeing an Oracle function version of this:
CREATE OR REPLACE FUNCTION unix_to_date(unix_sec NUMBER)
RETURN date
IS
ret_date DATE;
BEGIN
ret_date:=TO_DATE('19700101','YYYYMMDD')+( 1/ 24/ 60/ 60)*unix_sec;
RETURN ret_date;
END;
/
I had a bunch of records I needed dates for so I updated my table with:
update bobfirst set entered=unix_to_date(1500000000+a);
where a is a number between 1 and 10,000,000.
A shorter method to convert timestamp to nanoseconds.
SELECT (EXTRACT(DAY FROM (
SYSTIMESTAMP --Replace line with desired timestamp --Maximum value: TIMESTAMP '3871-04-29 10:39:59.999999999 UTC'
- TIMESTAMP '1970-01-01 00:00:00 UTC') * 24 * 60) * 60 + EXTRACT(SECOND FROM
SYSTIMESTAMP --Replace line with desired timestamp
)) * 1000000000 AS NANOS FROM DUAL;
NANOS
1598434427263027000
A method to convert nanoseconds to timestamp.
SELECT TIMESTAMP '1970-01-01 00:00:00 UTC' + numtodsinterval(
1598434427263027000 --Replace line with desired nanoseconds
/ 1000000000, 'SECOND') AS TIMESTAMP FROM dual;
TIMESTAMP
26/08/20 09:33:47,263027000 UTC
As expected, above methods' results are not affected by time zones.
A shorter method to convert interval to nanoseconds.
SELECT (EXTRACT(DAY FROM (
INTERVAL '+18500 09:33:47.263027' DAY(5) TO SECOND --Replace line with desired interval --Maximum value: INTERVAL '+694444 10:39:59.999999999' DAY(6) TO SECOND(9) or up to 3871 year
) * 24 * 60) * 60 + EXTRACT(SECOND FROM (
INTERVAL '+18500 09:33:47.263027' DAY(5) TO SECOND --Replace line with desired interval
))) * 1000000000 AS NANOS FROM DUAL;
NANOS
1598434427263027000
A method to convert nanoseconds to interval.
SELECT numtodsinterval(
1598434427263027000 --Replace line with desired nanoseconds
/ 1000000000, 'SECOND') AS INTERVAL FROM dual;
INTERVAL
+18500 09:33:47.263027
As expected, millis, micros and nanos are converted and reverted, dispite of SYSTIMESTAMP doesn't have nanosecounds information.
Replace 1000000000 by 1000, for example, if you'd like to work with milliseconds instead of nanoseconds.
I've tried some of posted methods, but almost of them are affected by the time zone or result on data loss after revertion, so I've decided do post the methods that works for me.

Convert elapsed time a decimal in Oracle

When performing the below calculation (end_time minus start_time) in Oracle you get a result of +00 01:30:00.000000. How can that result be converted to 1.50?
to_timestamp(to_char(end_time,'HH:MI AM'), 'HH:MI AM') -
to_timestamp(to_char(start_time,'HH:MI AM'), 'HH:MI AM')
Try something like this:
select dat,extract(hour from dat) ||'.'||trunc(100*extract(minute from dat)/60,0) result from
(select to_timestamp('04:30 AM', 'HH:MI AM') - to_timestamp('03:10 AM', 'HH:MI AM') as dat from dual union all
select to_timestamp('02:30 AM', 'HH:MI AM') - to_timestamp('02:00 AM', 'HH:MI AM') as dat from dual)
Results:
DAT RESULT
--------------------------------------------------------------------------------
+00 01:20:00.000000 1.33
+00 00:30:00.000000 0.50
The difference between two TIMESTAMPs is an INTERVAL. You can easily extract the various components and obtain the desired result with some arithmetics. In the general case (for a result in fractional days!):
with testdata as (
select NUMTODSINTERVAL(1.55,'DAY') i from dual
)
select EXTRACT(DAY FROM i)
+ EXTRACT(HOUR FROM i)/24
+ EXTRACT(MINUTE FROM i)/(24*60)
+ EXTRACT(SECOND FROM i)/(24*60*60)
FROM testdata
In your particular case, assuming (1) "timestamp is the data type" (2) you're "ignoring the day, second and millisecond components" (3) you want fractional hours :
select ...
EXTRACT(HOUR FROM (end_time-start_time))
+ EXTRACT(MINUTE FROM (end_time-start_time))/(60)
FROM ...
Alternative method: since your times are only accurate to the minute you may as well just use DATEs, subtraction of which yields a decimal number, e.g.:
to_date(to_char(end_time,'HH24:MI'), 'HH24:MI') -
to_date(to_char(start_time,'HH24:MI'), 'HH24:MI')
If the date portions are guaranteed to be on the same date, you can use an even simpler expression for the same result:
end_time - start_time

PL/SQL: TO_CHAR show format

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
))
/

Resources