How do I a convert a number to an INTERVAL of minutes? - oracle

In pseudo-Oracle, I want to do the following:
select systimestamp + to_interval(select NUMERIC_COLUMN from SOME_TABLE where SOME_TABLE_PK = :stuff) from dual;
If the number of minutes were always the same, I could use an interval literal a la interval '360' minute, but I can't find a simple function to convert a number to a MINUTE interval. What am I missing?

You can use the numtodsinterval function which does exactly the conversion you need (number to interval):
SQL> select systimestamp, systimestamp + numtodsinterval(20, 'MINUTE') from dual;
SYSTIMESTAMP SYSTIMESTAMP+NUMTODSINTERVAL(2
------------------------- -------------------------------
2011-08-22 16:12:24.060 2011-08-22 16:32:24.060

Related

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

sysdate to unix timestamp [duplicate]

I have a timestamp datatype in database with format 24-JuL-11 10.45.00.000000000 AM and want to get it converted into unix timestamp, how can I get it?
This question is pretty much the inverse of Convert Unixtime to Datetime SQL (Oracle)
As Justin Cave says:
There are no built-in functions. But it's relatively easy to write
one. Since a Unix timestamp is the number of seconds since January 1,
1970
As subtracting one date from another date results in the number of days between them you can do something like:
create or replace function date_to_unix_ts( PDate in date ) return number is
l_unix_ts number;
begin
l_unix_ts := ( PDate - date '1970-01-01' ) * 60 * 60 * 24;
return l_unix_ts;
end;
As its in seconds since 1970 the number of fractional seconds is immaterial. You can still call it with a timestamp data-type though...
SQL> select date_to_unix_ts(systimestamp) from dual;
DATE_TO_UNIX_TS(SYSTIMESTAMP)
-----------------------------
1345801660
In response to your comment, I'm sorry but I don't see that behaviour:
SQL> with the_dates as (
2 select to_date('08-mar-12 01:00:00 am', 'dd-mon-yy hh:mi:ss am') as dt
3 from dual
4 union all
5 select to_date('08-mar-12', 'dd-mon-yy')
6 from dual )
7 select date_to_unix_ts(dt)
8 from the_dates
9 ;
DATE_TO_UNIX_TS(DT)
-------------------
1331168400
1331164800
SQL>
There's 3,600 seconds difference, i.e. 1 hour.
I realize an answer has already been accepted, but I think it should be made clear that the function in that answer doesn't consider the passed in date's time zone offset. A proper Unix timestamp should be calculated at GMT (+0). Oracle's to_date function assumes the passed in date is in the local time zone unless otherwise specified. This problem is exacerbated by the fact that Daylight Saving Time is a real thing. I over came this problem with the following function:
create or replace
function unix_time_from_date
(
in_date in date,
in_src_tz in varchar2 default 'America/New_York'
)
return integer
as
ut integer := 0;
tz varchar2(8) := '';
tz_date timestamp with time zone;
tz_stmt varchar2(255);
begin
/**
* This function is used to convert an Oracle DATE (local timezone) to a Unix timestamp (UTC).
*
* #author James Sumners
* #date 01 February 2012
*
* #param in_date An Oracle DATE to convert. It is assumed that this date will be in the local timezone.
* #param in_src_tz Indicates the time zone of the in_date parameter.
*
* #return integer
*/
-- Get the current timezone abbreviation (stupid DST)
tz_stmt := 'select systimestamp at time zone ''' || in_src_tz || ''' from dual';
execute immediate tz_stmt into tz_date;
select
extract(timezone_abbr from tz_date)
into tz
from dual;
-- Get the Unix timestamp
select
(new_time(in_date, tz, 'GMT') - to_date('01-JAN-1970', 'DD-MM-YYYY')) * (86400)
into ut
from dual;
return ut;
end unix_time_from_date;
I have some companion functions, unix_time and unix_time_to_date, available at http://jrfom.com/2012/02/10/oracle-and-unix-timestamps-revisited/. I can't believe Oracle has made it all the way to 11g without implementing these.
for date:
FUNCTION date_to_unix (p_date date,in_src_tz in varchar2 default 'Europe/Kiev') return number is
begin
return round((cast((FROM_TZ(CAST(p_date as timestamp), in_src_tz) at time zone 'GMT') as date)-TO_DATE('01.01.1970','dd.mm.yyyy'))*(24*60*60));
end;
for timestamp:
FUNCTION timestamp_to_unix (p_time timestamp,in_src_tz in varchar2 default 'Europe/Kiev') return number is
begin
return round((cast((FROM_TZ(p_time, in_src_tz) at time zone 'GMT') as date)-TO_DATE('01.01.1970','dd.mm.yyyy'))*(24*60*60));
end;
I'm using following method, which differs a little from other answers in that it uses sessiontimezone() function to properly get date
select
(
cast((FROM_TZ(CAST(in_date as timestamp), sessiontimezone) at time zone 'GMT') as date) -- in_date cast do GMT
-
TO_DATE('01.01.1970','dd.mm.yyyy') -- minus unix start date
)
* 86400000 -- times miliseconds in day
from dual;
This was what I came up with:
select substr(extract(day from (n.origstamp - timestamp '1970-01-01 00:00:00')) * 24 * 60 * 60 +
extract(hour from (n.origstamp - timestamp '1970-01-01 00:00:00')) * 60 * 60 +
extract(minute from (n.origstamp - timestamp '1970-01-01 00:00:00')) * 60 +
trunc(extract(second from (n.origstamp - timestamp '1970-01-01 00:00:00')),0),0,15) TimeStamp
from tablename;
FWIW
SELECT (SYSDATE - TO_DATE('01-01-1970 00:00:00', 'DD-MM-YYYY HH24:MI:SS')) * 24 * 60 * 60 * 1000 FROM DUAL
For conversion between Oracle time and Unix times I use these functions.
They consider your current timezone. You should also add DETERMINISTIC keyword, for example if you like to use such function in a function-based index. Conversion between DATE and TIMESTAMP should be done implicitly by Oracle.
FUNCTION Timestamp2UnixTime(theTimestamp IN TIMESTAMP, timezone IN VARCHAR2 DEFAULT SESSIONTIMEZONE) RETURN NUMBER DETERMINISTIC IS
timestampUTC TIMESTAMP;
theInterval INTERVAL DAY(9) TO SECOND;
epoche NUMBER;
BEGIN
timestampUTC := FROM_TZ(theTimestamp, timezone) AT TIME ZONE 'UTC';
theInterval := TO_DSINTERVAL(timestampUTC - TIMESTAMP '1970-01-01 00:00:00');
epoche := EXTRACT(DAY FROM theInterval)*24*60*60
+ EXTRACT(HOUR FROM theInterval)*60*60
+ EXTRACT(MINUTE FROM theInterval)*60
+ EXTRACT(SECOND FROM theInterval);
RETURN ROUND(epoche);
END Timestamp2UnixTime;
FUNCTION UnixTime2Timestamp(UnixTime IN NUMBER) RETURN TIMESTAMP DETERMINISTIC IS
BEGIN
RETURN (TIMESTAMP '1970-01-01 00:00:00 UTC' + UnixTime * INTERVAL '1' SECOND) AT LOCAL;
END UnixTime2Timestamp;
I agree to what Wernfried Domscheit and James Sumners explained in their posts as solutions - mainly because of the timezone and summertime/wintertime issue !
One of the functions I prefer shorter and without dynamic SQL:
-- as Date
CAST ( FROM_TZ( TIMESTAMP '1970-01-01 00:00:00' + NUMTODSINTERVAL(input_date , 'SECOND') , 'GMT' ) AT TIME ZONE 'Europe/Berlin' AS DATE )
or
-- as Timestamp
FROM_TZ( to_timestamp(Date '1970-01-01' + input_date / 86400 ), 'GMT' ) AT TIME ZONE 'Europe/Berlin'
As "Time Zone" one needs to put the static string (ie 'Europe/Berlin') and not the dbtimezone or sessiontimezone variable, because this might yield a wrong offset because the execution time can be in Summer while the unix Timestamp could be in winter.
All the above do this:-
ORA-01873: the leading precision of the interval is too small
if your dates are TIMESTAMP format.
Here's the correct answer (assuming you're smart enough to have set up your server to use UTC.)
select (cast(sys_extract_utc(current_timestamp) as date) - TO_DATE('1970-01-01 00:00:00','YYYY-MM-DD HH24:MI:SS')) * 86400 as gmt_epoch from dual;
SELECT
to_char(sysdate, 'YYYY/MM/DD HH24:MI:SS') dt,
round((sysdate - to_date('19700101 000000', 'YYYYMMDD HH24MISS'))*86400) as udt
FROM dual;

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.

Alter a datetime in Oracle and set time to 9 am

i have 28-APR-2016 10:05:07 date as parameter in stored procedure. This may be the current time also as string date.
i need to set the time to 9 am to check the shift start timing.
SELECT TO_DATE('28-APR-2016 10:05:07', 'DD-MON-YYYY HH24:MI:SS') FROM dual;
I am new to oracle. Help is appreciated.
If you want the date with 9:00 a.m., then you can do:
SELECT TRUNC(TO_DATE('28-APR-2016 10:05:07', 'DD-MON-YYYY HH24:MI:SS')) + 9/24.0
FROM dual;
You can also use:
SELECT TRUNC(TO_DATE('28-APR-2016 10:05:07', 'DD-MON-YYYY HH24:MI:SS')) + INTERVAL '9' HOUR
FROM dual;
I'm just old-fashioned so I tend to use the first method.

Subtracting/Adding to a Where clause timestamp condition

I'm attempting to speed up a timestamp comparison query by restricting the query to 30 minutes before and after the timestamp in question. This is the format I'm using:
Causedat
-----
11-NOV-15 10.20.58.000000000 AM
11-NOV-15 10.19.41.877000000 AM
10-NOV-15 11.01.40.000000000 AM
10-NOV-15 11.00.50.460000000 AM
05-NOV-15 01.53.30.966000000 PM
05-NOV-15 01.47.31.000000000 PM
What I'm trying to do is write a condition where i'll tell the system only to look for dates in the system that are +-00:30:00.000000000 (thirty minutes) from the Causedat date in the future or past from that time.
I've seen that for example, SYSDATE - SYSTIMESTAMP is a legitimate calculation. Is it possible to do something similar to this like this:
WHERE search.date >= (Causedat = Causedat - '000000000 00:30:00.000000000')
AND search.date <= (Causedat = Causedat + '000000000 00:30:00.000000000')
Please assume the date i'm searching and Causedat are in the same (timestamp) format for this question.
Thank you for any light you may be able to shine on the problem for me.
You can add an interval to a timestamp; you can read about datetime and interval arithmetic. There are conversion functions to go from a variable to an interval, but with known fixed values you can use an interval literal here. You can use the full string you have:
where search_date >= causedat - interval '000000000 00:30:00.000000000' day to second
and search_date <= causedat + interval '000000000 00:30:00.000000000' day to second;
Or just the non-zero part:
where search_date >= causedat - interval '30' minute
and search_date <= causedat + interval '30' minute;
Trivial demo of how these evaluate:
select systimestamp,
systimestamp - interval '000000000 00:30:00.000000000' day to second as minus_30,
systimestamp + interval '000000000 00:30:00.000000000' day to second as plus_30
from dual;
SYSTIMESTAMP MINUS_30 PLUS_30
----------------------------------- ----------------------------------- -----------------------------------
18-NOV-15 11.39.09.597473000 +00:00 18-NOV-15 11.09.09.597473000 +00:00 18-NOV-15 12.09.09.597473000 +00:00
select systimestamp,
systimestamp - interval '30' minute as minus_30,
systimestamp + interval '30' minute as plus_30
from dual;
SYSTIMESTAMP MINUS_30 PLUS_30
----------------------------------- ----------------------------------- -----------------------------------
18-NOV-15 11.39.09.653809000 +00:00 18-NOV-15 11.09.09.653809000 +00:00 18-NOV-15 12.09.09.653809000 +00:00
Direct arithmetic on date time column with required interval value.
WHERE search.date
BETWEEN Causedat - INTERVAL '30' MINUTE
AND Causedat + INTERVAL '30' MINUTE
I just went through the question. I have provided a simple example to illustrate how we can achieve this.
SELECT A.DT
FROM
( SELECT SYSTIMESTAMP - INTERVAL '60' MINUTE AS DT FROM DUAL
UNION
SELECT SYSTIMESTAMP - INTERVAL '30' MINUTE AS DT FROM DUAL
UNION
SELECT SYSTIMESTAMP AS DT FROM DUAL
UNION
SELECT SYSTIMESTAMP + INTERVAL '30' MINUTE AS DT FROM DUAL
UNION
SELECT SYSTIMESTAMP + INTERVAL '60' MINUTE AS DT FROM DUAL
)A
WHERE A.DT BETWEEN (SYSTIMESTAMP - INTERVAL '30' MINUTE) AND (SYSTIMESTAMP + INTERVAL '30' MINUTE);
Let me know if this helps.

Resources