Convert elapsed time a decimal in Oracle - 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

Related

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

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.

Wrong difference in minutes in Oracle (DATE2-DATE1)*24*60

I'm trying to calculate difference in minutes between two dates in Oracle with this testing query:
SELECT
(DATE2-DATE1)*24*60 DIFFINMINUTES
FROM
(
SELECT
TO_DATE('2014-06-06 10:30:00', 'YYYY-MM-DD HH24:MI:SS') DATE1,
TO_DATE('2014-06-06 11:25', 'YYYY-MM-DD HH24:MI') DATE2
FROM DUAL
);
The expected result should be 55 minutes but I'm getting 54,99999999.
ROUNDing this value gets the job done but I really wants to understand why this calculation was this behavior.
DATE2 - DATE1 Oracle calculates the difference in days. That's why some inaccuracy may occur.
Just an example with timestamps
select inter,
extract (day from inter) days,
extract (hour from inter) hours,
extract (minute from inter) minutes,
extract (second from inter) seconds
from
(select
cast(date2 as timestamp) - cast(date1 as timestamp) inter
FROM
(
SELECT
TO_DATE('2014-06-06 10:30:00', 'YYYY-MM-DD HH24:MI:SS') DATE1,
to_date('2014-06-06 11:25', 'YYYY-MM-DD HH24:MI') date2
from dual
));
Substraction of timestamps gives you exact INTERVAL

How to strip Timestamp up to just seconds?

Given a timestamp value, i.e. "04-SEP-14 03.09.09.272949000 PM", how do I get the date time up to just the seconds part and zeroing out the micro-seconds part?
given: 04-SEP-14 03.09.09.272949000 PM
wish: 04-SEP-14 03.09.09.00 PM
thanks in advance.
You can use the cast function to cast it to a zero-millisecond TIMESTAMP with the construct:
cast(<your column>, timestamp(0))
Using a CTE to pass in your value:
with t as (
select to_timestamp('04-SEP-14 03.09.09.272949000 PM',
'DD-MON-RR HH:MI:SS.FF AM') as tstamp
from dual
)
select to_char(cast(tstamp as timestamp(0)), 'DD-MON-RR HH:MI:SS.FF2 AM')
from t;
TO_CHAR(CAST(TSTAMPASTIMESTAMP(0)),'DD-M
----------------------------------------
04-SEP-14 03:09:09.00 PM
You could also cast it twice, once to DATE to strip the milliseconds, and then back to TIMESTAMP again:
with t as (
select to_timestamp('04-SEP-14 03.09.09.272949000 PM',
'DD-MON-RR HH:MI:SS.FF AM') as tstamp
from dual
)
select to_char(cast(cast(tstamp as date) as timestamp),
'DD-MON-RR HH:MI:SS.FF2 AM')
from t;
TO_CHAR(CAST(CAST(TSTAMPASDATE)ASTIMESTA
----------------------------------------
04-SEP-14 03:09:09.00 PM
... which is doing more work as well as being more typing.
You can't use trunc(date) because that implicitly converts the TIMESTAMP to a DATE, and since a DATE is already at that precision you can't pass SS as the fmt anyway.

to_timestamp encounter the fractional seconds must be between 0 and 999999999

enter code herethis is the code
select to_timestamp('03-APR-13 01.15.31.6754542 PM','DD-MON-RR HH.MI.SS.FF4 AM') from dual;
i originally intended to accurate millisecond to 4 digits,but the error display.and i find if the digits of .ff is equal or greater than 7 which is the digits of 6754542,
for example:
select to_timestamp('03-APR-13 01.15.31.6754542 PM','DD-MON-RR HH.MI.SS.FF8 AM') from dual;
select to_timestamp('03-APR-13 01.15.31.6754542 PM','DD-MON-RR HH.MI.SS.FF9 AM') from dual;
and so on. they always disply 03-APR-13 01.15.31.675454200 PM,9 digits...
how can i accurate millisecond to 4 digits,or forever not?
please help me,thanks.
SELECT
TO_CHAR(
TO_TIMESTAMP('03-APR-13 01.15.31.6754542 PM',
'DD-MON-RR HH.MI.SS.FF AM'),
'DD-MON-RR HH.MI.SS.FF4 AM')
FROM DUAL;

Resources