Any ways to calculate exact time between two timestamp with timezone - sql

is there any way in oracle to calculate the difference between two time stamps value with time zones in oracle sql plus as it is not possible to use timestampdiff or datediff inside oracle.
Thanks

Just subtract them:
SQL> select (systimestamp + 1) - systimestamp from dual;
(SYSTIMESTAMP+1)-SYSTIMESTAMP
---------------------------------------------------------------------------
+000000000 23:59:59.884789

Consider the following in case you need the number of milliseconds between two timestamps:
create or replace Function msecBetween
(ts1 timestamp with time zone,
ts2 timestamp with time zone,
numDec number default 0
)
Return Number is
i INTERVAL DAY(3) TO SECOND(3) := ts2 - ts1;
Begin
return round (
+ extract( day from i )*24*60*60*1000
+ extract( hour from i )*60*60*1000
+ extract( minute from i )*60*1000
+ extract( second from i )*1000
, numDec);
End;

Related

How to substract 2 varchar dates in oracle?

I have these varchar : 20211026231735.
So I would like a query to substract actual sysdate to that date and convert the substraction to DAY HOURS AND SECONDS.
select TO_CHAR(SYSDATE,'YYYYMMDDHH24MISS') - start_time from TABLEA where job_name='jOB_AA_BB';
I get 4220.
Any help please? Thanks
When you do datetime arithmetic with the DATE datatype, you get back a NUMBER of days. To get an INTERVAL you can subtract two TIMESTAMPs. You don't say what the data type is for start_time, but you might get away with this:
select localtimestamp - start_time
from tablea where job_name='jOB_AA_BB';
LOCALTIMESTAMP gives you a TIMESTAMP value in the current session time zone. There's also CURRENT_TIMESTAMP, which give you the same thing in a TIMESTAMP WITH TIME ZONE and SYSTIMESTAMP that gives you the database time in TIMESTAMP WITH TIME ZONE. You may need to convert your start_time to avoid time zone differences, if any.
You can us the function numtodsinterval to convert the results of date arithmetic to an interval. If necessary then use extract to pull out the needed components.
with tablea(job_name, start_time) as
(select 'jOB_AA_BB','20211026231735' from dual)
select numtodsinterval((SYSDATE - to_date( start_time,'yyyymmddhh24miss')),'hour') date_diff
from tablea where job_name='jOB_AA_BB' ;
with tablea(job_name, start_time) as
(select 'jOB_AA_BB','20211026231735' from dual)
select extract (hour from date_diff) || ':' || extract (minute from date_diff)
from (
select numtodsinterval((sysdate - to_date( start_time,'yyyymmddhh24miss')),'day') date_diff
from tablea where job_name='jOB_AA_BB'
);
NOTE: I am not sure how you got any result, other than an error, as your query winds up as a string - a string. You should not convert sysdate to a string but your string to a date (better yet store it as the proper data type - date).
You can convert the value to a date (rather than converting SYSDATE to a string) and then subtract and explicitly return the value as an INTERVAL DAY TO SECOND type:
SELECT (SYSDATE - TO_DATE('20211026231735', 'YYYYMMDDHH24MISS')) DAY TO SECOND
FROM DUAL;
Or, for your table:
SELECT (SYSDATE - TO_DATE(start_time,'YYYYMMDDHH24MISS')) DAY(5) TO SECOND
FROM TABLEA
WHERE job_name='jOB_AA_BB';
db<>fiddle here

postgres convert a substring to epoch

I'm trying to convert a epoch timestamp to a human readable timestamp in a single query but I'm getting a little stuck - any help is appreciated.
testing=# SELECT creation_time FROM users LIMIT 1;
creation_time
---------------
1354006445722
(1 row)
testing=# SELECT SUBSTRING('1498123813330', 1,10);
SUBSTRING
------------
1498123813
(1 row)
testing=# SELECT TIMESTAMP WITH TIME ZONE 'epoch' + 1498123813 * INTERVAL '1 second';
?column?
------------------------
2017-06-22 02:30:13-07
(1 row)
Anyway to put this into a single query?
What you want is CASTing, i.e.
SELECT TIMESTAMP WITH TIME ZONE 'epoch' +
SUBSTRING(creation_time, 1, 10)::NUMERIC * INTERVAL '1 second';
But, if creating time is epoch milliseconds, you could do:
SELECT to_timestamp(creation_time::double precision / 1000)
instead, which will preserve milliseconds too. You can print timestamp out with to_char if you want a format, other than the default timestamp output.
http://rextester.com/EHPNJ86308
Assuming created_time is stored as a varchar, you can apply the same substring logic to it and cast it to a number:
SELECT TIMESTAMP WITH TIME ZONE 'epoch' +
SUBSTRING(creation_time, 1,10)::NUMERIC * INTERVAL '1 second'
FROM users

Add two hours to timestamp

I've got a trigger that has to set a timestamp to the current time plus two hours when the field is null before insert. One of the statements I tried so far is
IF :new.time_to_live IS NULL THEN
:new.time_to_live := sysdate + INTERVAL '0 02:00:00.0' HOUR TO MINUTE;
END IF;
but I get a PLS-00166 Error (bad format for date, time, timestamp or interval literal) for the second row. Also modified it to several suggestions in multiple forums but the error stays. The column is created as follows:
time_to_live timestamp(0) NOT NULL
You need to change your HOUR TO MINUTE to match the value you're actually passing:
sysdate + INTERVAL '0 02:00:00.0' DAY TO SECOND
You might also want to use systimestamp instead of sysdate. You can use a shorter interval literal too if you're always adding exactly two hours:
systimestamp + INTERVAL '02:00' HOUR TO MINUTE
or just
systimestamp + INTERVAL '2' HOUR
As a quick demo:
SELECT systimestamp, systimestamp + INTERVAL '2' HOUR FROM DUAL;
SYSTIMESTAMP SYSTIMESTAMP+INTERVAL'2'HOUR
----------------------------------- -----------------------------------
11-MAY-15 11.15.22.235029000 +01:00 11-MAY-15 13.15.22.235029000 +01:00
Alther interval can really be convenient, I often write this as:
IF :new.time_to_live IS NULL THEN
:new.time_to_live := sysdate + 2 / 24.0
END IF;
Adding an integer to a date is treated as a number of days. "2 / 24" is two hours.

timestamp having milliseconds convert to seconds in oracle

I captured request and response time for procedure i need to calculate time take by substract both request -response to find time taken.
P_REQUEST_TIME :='20/MAR/2014 03:03:50.785662 PM';
P_RESPONSE_TIME :='20/MAR/2014 03:03:50.785816 PM';
SELECT TO_TIMESTAMP(P_REQUEST_TIME)-TO_TIMESTAMP(P_RESPONSE_TIME)
into l_actual_time
FROM dual;
Getting result is Result:='-000000000 00:00:00.000154000';
I need this as seconds.
Use EXTRACT function.
SELECT EXTRACT(SECOND FROM TO_TIMESTAMP(P_REQUEST_TIME)-TO_TIMESTAMP(P_RESPONSE_TIME)) diff_seconds
FROM <table_name>;
select extract( day from diff ) days,
extract( hour from diff ) hours,
extract( minute from diff ) minutes,
extract( second from diff ) seconds
from (SELECT TO_TIMESTAMP(REQUEST_DTTM)-TO_TIMESTAMP(RESPONS_DTTM) diff FROM hit_tracer);
if u want the difference between two timestamps in seconds, this is the query
SELECT (P_REQUEST_TIME-P_RESPONSE_TIME) *24 *60*60
into l_actual_time
FROM dual;

Convert milliseconds to Timestamp

I know that to convert a Unix timestamp in milliseconds to an SQL timestamp I can use
SELECT TO_DATE('1970-01-01','YYYY-MM-DD HH24:MI:SS') +
(:timestamp / (1000*60*60*24)) FROM DUAL;
But I need a Timestamp, so I tried with
SELECT TO_TIMESTAMP('1970-01-01 00:00:00','YYYY-MM-DD HH24:MI:SSFF3') +
(:timestamp) from DUAL
Which gives me the error:
Error: ORA-01841: (full) year must be between -4713 and +9999, and not be 0
It seems that adding 1 to the timestamp always converts it to a day.
How can I do the same to get a real timestamp?
You will get a timestamp if you add an interval to a timestamp (see date/interval arithmetics).
As Benoit noticed, you can't specify an interval with seconds when there are more than about 2.1e9 of them:
SQL> SELECT numtodsinterval(2.2e9, 'SECOND'),
2 numtodsinterval(2.3e9, 'SECOND')
3 FROM dual;
NUMTODSINTERVAL(2.2E9,'SECOND' NUMTODSINTERVAL(2.3E9,'SECOND'
------------------------------- -------------------------------
+000024855 03:14:07.147483647 +000024855 03:14:07.147483647
This is why you should use minutes which do not lose precision. For example, assuming :TS is the unix timestamp (i.e. a number):
SQL> variable ts number;
SQL> -- determining unix timestamp with nanosecond precision
SQL> BEGIN
2 :ts := (to_date('2099-01-01 01:02:03', 'yyyy-mm-dd hh24:mi:ss')
3 - date '1970-01-01') * 1000*60*60*24
4 + 123.456789;
5 END;
6 /
ts
---------
4070912523123,456789
SQL> select timestamp '1970-01-01 00:00:00'
2 + numtodsinterval((:ts)/1000/60, 'MINUTE')
3 from dual;
TIMESTAMP'1970-01-0100:00:00'+NUMTODSINTERVAL((:TS)/1000/60,'MINUTE')
---------------------------------------------------------------------------
2099-01-01 01:02:03.123456789
There are two types:
Timestamps
Intervals
Intervals is what you get when you subtract timestamps, and it is nonsensical to add timestamps together.
If you need to get a millisecond interval, I would suggest to use a second interval and divide it by 1000:
I could suggest:
SELECT timestamp'1970-01-01 00:00:00' + (interval '1888' second(9) / 1000)
FROM dual
The problem here is that you cannot use more than 9 digits in a same timestamp literal.
If you need to ad 2,061,464,797,255 milliseconds to the epoch I can suggest:
SELECT TIMESTAMP'1970-01-01 00:00:00'
+ INTERVAL '2' SECOND(9) * 1000000000
+ INTERVAL '061464797' SECOND(9)
+ INTERVAL '255' SECOND(3) / 1000
FROM dual
You get 2035-04-29 13:06:37.255000000
It seems to be subject to the 2038 bug: TIMESTAMP'1970-01-01 00:00:00' + 3 billion seconds does not work, whereas it works with 2 billion.
I've posted here some methods to convert nanoseconds to timestamp and timestamp to nanoseconds. These methods are not affected by time zones and have a nanosecond precision.
You just need to adjust it to use milliseconds instead of nanoseconds.
SELECT TIMESTAMP '1970-01-01 00:00:00 UTC' + numtodsinterval(
1598434427263 --Replace line with desired milliseconds
/ 1000, 'SECOND') AS TIMESTAMP FROM dual;
TIMESTAMP
26/08/20 09:33:47,263000000 UTC
Use
SELECT TIMESTAMP '1970-01-01 00:00:00.1234' + INTERVAL '1 00:00:00' DAY TO SECOND
AS ts
FROM dual;