Convert epoch to date in sqlplus / Oracle - oracle

I have the following table:
SQL> desc recording
Name Null? Type
-------------------- -------- ------
CAPTUREID NOT NULL NUMBER(9)
STARTDATE NOT NULL DATE
ENDDATE DATE
STATE NUMBER(1)
ESTIMATEDENDTIME NUMBER(13)
Here's a single line for this table:
SQL> select * from recording where CAPTUREID=14760457;
CAPTUREID STARTDATE ENDDATE STATE ESTIMATEDENDTIME
---------- ------------------- ------------------- ----- ----------------
14760457 29/09/2010 08:50:01 29/09/2010 09:52:04 0 1285746720000
I'm pretty sure that this has been asked so many times before, but all the solutions I've found so far didn't really work, so... How do I convert ESTIMATEDENDTIME from its original epoch form to a DD/MM/YYY HH:MI:SS format in a single query in SQLPLUS?
Thanks!

In Oracle, adding X to a DATE will return you a DATE X days later.
If ESTIMATEDENDTIME is milliseconds since Epoch then you could do
DATE '1970-01-01' + ( 1 / 24 / 60 / 60 / 1000) * ESTIMATEDENDTIME
and then use to_char to achieve the correct format of the resulting date. e.g:
SELECT
captureid
, startdate
, enddate
, state
, estimatedendtime
, DATE '1970-01-01' + ( 1 / 24 / 60 / 60 / 1000) * estimatedendtime AS estimatedenddate
FROM recording

select ((timestamp_coloum_name - to_date('01-JAN-1970','DD-MON-YYYY')) * (86400)) from any_table;

Related

Charts in Oracle Apex

Hi everyone I wanna ask u about how I can bring data last 24 hours into bar charts, is there any methods to make it please
I have this table without data
datetime
clientchannel
servicename
service_count
13_02_2022 9:35
*****
notification
2
It is a WHERE clause you need, I presume. Something like this:
select ...
from your_table
where datetime >= sysdate - 1;
Why? Because - when you subtract a number from DATE datatype value in Oracle - it subtracts that many days.
SQL> alter session set nls_date_format = 'dd.mm.yyyy hh24:mi:ss';
Session altered.
SQL> select sysdate right_now,
2 sysdate - 1 yesterday
3 from dual;
RIGHT_NOW YESTERDAY
------------------- -------------------
13.02.2022 11:01:34 12.02.2022 11:01:34
SQL>
If you store date values as strings (which means that DATETIME column is declared as e.g. VARCHAR2(20), and that's really bad idea), then you first have to convert it to a valid date datatype value - use TO_DATE function with appropriate format mask:
where to_date(datetime, 'dd_mm_yyyy hh24:mi') >= sysdate - 1
[EDIT] If you want to go 60 minutes back, then subtract that many minutes:
SQL> select sysdate right_now,
2 sysdate - interval '60' minute an_hour_ago
3 from dual;
RIGHT_NOW AN_HOUR_AGO
------------------- -------------------
14.02.2022 07:09:30 14.02.2022 06:09:30
SQL>

Oracle - Extract Year from date result in 0 [duplicate]

This question already has an answer here:
Trying to export a Oracle via PL/SQL gives a date of 0000-00-00
(1 answer)
Closed 1 year ago.
Duplicate of Trying to export a Oracle via PL/SQL gives a date of 0000-00-00 as mentioned by #AlexPoole
I have a table with different dates in it, however, when I try to extract year, a single row returns an incorrect result.
This incorrect result happens when I execute the following (note that TO_DATE and FROM_DATE are both of data_type DATE):
select
TO_DATE
,EXTRACT(YEAR FROM TO_DATE) as "TO_YEAR"
,EXTRACT(MONTH FROM TO_DATE) as "TO_MONTH"
,EXTRACT(DAY FROM TO_DATE) as "TO_DAY"
,FROM_DATE
,EXTRACT(YEAR FROM FROM_DATE) as "FROM_YEAR"
,EXTRACT(MONTH FROM FROM_DATE) as "FROM_MONTH"
,EXTRACT(DAY FROM FROM_DATE) as "FROM_DAY"
,DUMP(FROM_DATE, 1016) as FROM_DUMP
,to_char(FROM_DATE, 'SYYYY-MM-DD HH24:MI:SS') FROM_STRING
from SomeTable
The incorrect result is (date format is YY-MM-DD):
TO_DATE TO_YEAR TO_MONTH TO_DAY FROM_DAT FROM_YEAR FROM_MONTH FROM_DAY FROM_DUMP FROM_STRING
-------- ---------- ---------- ---------- -------- ---------- ---------- ---------- ----------------------------- --------------------
00-02-01 2000 2 1 01-02-01 0 2 1 Typ=12 Len=7: 64,64,2,1,1,1,1 00000-00-00 00:00:00
My question is why does FROM_YEAR return a zero and not 2001?
A DATE is stored in 7-bytes using:
century + 100
year-of-century + 100
month + 0
day + 0
hour + 1
minute + 1
second + 1
Looking at the output of DUMP, which is Typ=12 Len=7: 64,64,2,1,1,1,1 then you have:
Century = -36
Year-of-century = -36
Month = February
Day = 1
Hour = 0
Minute = 0
Year = 0
Which would make your date midnight of 1st February 3636 BC.
Unless you intended to use dates from ancient history then it would suggest that somewhere in your application some corrupted data has been stored.
However, something else appears to be going on as that is a valid date that can be stored and TO_CHAR should work.
CREATE TABLE table_name ( dt ) AS
SELECT DATE '-3636-02-01'FROM DUAL;
SELECT TO_CHAR( dt, 'SYYYY-MM-DD HH24:MI:SS' ) AS dt_string,
DUMP( dt )
FROM table_name;
Outputs:
DT_STRING
DUMP(DT)
-3636-02-01 00:00:00
Typ=12 Len=7: 64,64,2,1,1,1,1
db<>fiddle here
and the DUMP matches your data but the TO_CHAR output is valid whereas yours is zeros.

checking expiryDate in Oracle query

I have a table which contains the start date, ExpiryDate, I want to write an oracle query which checks if the expiry date is greater than the current system date, Then I want to return that row, else null will be the result of the query.
I wrote something like this,
select Name,Password,StartDate,ExpiryDate from db_name where UserName = 'abc' and status =1 and ExpiryDate >=(SELECT Round((sysdate - to_date('01-JAN-1970','DD-MON-YYYY')) * (86400))*1000 as dt FROM dual);
Here is the table description:
STARTDATE NOT NULL NUMBER(20)
EXPIRYDATE NOT NULL NUMBER(20)
The values:
EXPIRYDATE
----------
1.5880E+12
after performing query like select to_char(startdate),to_char(expirydate) I am getting
TO_CHAR(STARTDATE)
----------------------------------------
TO_CHAR(EXPIRYDATE)
----------------------------------------
1587909960000
1587996480000
But it is working fine for all cases, but if the expiry date is less than( the current time+6hrs) it is giving null, can anyone tell me how to solve this?
Unix epoch time is in the UTC time zone. You can convert the current time to UTC time zone and then subtract the epoch:
SELECT Name,
Password,
StartDate,
ExpiryDate
FROM IM_USER_MANAGEMENT
WHERE UserName = 'abc'
AND status =1
AND ExpiryDate >= ( CAST( SYSTIMESTAMP AT TIME ZONE 'UTC' AS DATE )
- DATE '1970-01-01'
)*24*60*60*1000
Unix epoch time, eh? See if this helps.
Set date format to something recognizable:
SQL> alter session set nls_date_format = 'dd.mm.yyyy hh24:mi:ss';
Session altered.
Sample data:
SQL> select * From test;
STARTDATE EXPIRYDATE
---------------------- ----------------------
1587909960000 1587996480000
Converted to DATE values:
SQL> select
2 date '1970-01-01' + ( 1 / 24 / 60 / 60 / 1000) * startdate startdt,
3 date '1970-01-01' + ( 1 / 24 / 60 / 60 / 1000) * expirydate expdt
4 from test;
STARTDT EXPDT
------------------- -------------------
26.04.2020 14:06:00 27.04.2020 14:08:00
Or, using it along with sysdate:
SQL> select *
2 from test
3 where sysdate between
4 date '1970-01-01' + ( 1 / 24 / 60 / 60 / 1000) * startdate and
5 date '1970-01-01' + ( 1 / 24 / 60 / 60 / 1000) * expirydate;
STARTDATE EXPIRYDATE
---------------------- ----------------------
1587909960000 1587996480000
As sysdate currently is:
SQL> select sysdate from dual;
SYSDATE
-------------------
27.04.2020 12:45:56
It looks to me like these dates of yours are Javascript style timestamps. That is, it looks like they are times since the UNIX epoch 1970-01-01 00:00:00 UTC measured in milliseconds. Notice they're with reference to UTC, not your local time zone. Is your time zone Asia/Dhaka? That's the one six hours ahead of UTC.
It also looks to me like your timestamps have ten-second precision. The two you showed are divisible by 10 000.
This is the formula for converting Javascript times to Oracle UTC date/time values
SELECT TO_DATE('19700101','yyyymmdd') + (1587909960000/86400000) FROM DUAL;
This yields a SYSDATE - style rendering of your values in UTC time, not local time. It yields 2020-04-26 14:06:00
Because you have a six-hour apparent error, I guess your local time zone is Asia/Dhaka, UTC+6. But it also could possibly be America/Denver, UTC-6.
and your time value, run through that formula, yields 2020-04-26 14:06:00. Which seems like a valid recent date/time.
This is a GUESS! If you're working with other peoples' money or lives in your database, ask the person who programmed it. It's not a DBMS-native way of doing things, so you should double-check.
What's going on in the formula?
In Oracle, adding 1.0 to a SYSDATE - style value adds one calendar day to it. So we start with the Oracle date for the UNIX epoch TO_DATE('19700101','yyyymmdd').
Then we take your millisecond timestamp value and convert it to days, dividing by 86 400 000, Finally we add it to the epoch date.
Here are some suggestions about getting the current time in UTC, so you can compare it to your timestamp data. How to get UTC value for SYSDATE on Oracle

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;

Time difference in oracle

Hi i have the following table which contains Start time,end time, total time
STARTTIME | ENDTIME | TOTAL TIME TAKEN |
02-12-2013 01:24:00 | 02-12-2013 04:17:00 | 02:53:00 |
I need to update the TOTAL TIME TAKEN field as above using the update query in oracle
For that I have tried the following select query
select round((endtime-starttime) * 60 * 24,2),
endtime,
starttime
from purge_archive_status_log
but I'm getting 02.53 as a result, but my expectation format is 02:53:00 Please let me know how can I do this?
There is probably no reason to have that total_time_taken column in your table at all, you can always calculate it's value. But If you insist on keeping it, it would be better to recreated it as column of interval day to second data type, not varchar2(assuming that that's its current data type). So here are two queries for you to choose from, one returns value of interval day to second data type and another one value of varchar2 data type:
This query returns difference between two dates as a value of interval day to second data type:
SQL> with t1(starttime, endtime, total_time_taken ) as(
2 select to_date('02-12-2013 01:24:00', 'dd/mm/yyyy hh24:mi:ss')
3 , to_date('02-12-2013 04:17:00', 'dd/mm/yyyy hh24:mi:ss')
4 , '02:53:00'
5 from dual
6 )
7 select starttime
8 , endtime
9 , (endtime - starttime) day(0) to second(0) as total_time_taken
10 from t1
11 ;
Result:
STARTTIME ENDTIME TOTAL_TIME_TAKEN
----------- ----------- ----------------
02-12-2013 01:24:00 02-12-2013 04:17:00 +0 02:53:00
This query returns difference between two dates as a value of varchar2 data type:
SQL> with t1(starttime, endtime, total_time_taken ) as(
2 select to_date('02-12-2013 01:24:00', 'dd/mm/yyyy hh24:mi:ss')
3 , to_date('02-12-2013 04:17:00', 'dd/mm/yyyy hh24:mi:ss')
4 , '02:53:00'
5 from dual
6 )
7 select starttime
8 , endtime
9 , to_char(extract(hour from res), 'fm00') || ':' ||
10 to_char(extract(minute from res), 'fm00') || ':' ||
11 to_char(extract(second from res), 'fm00') as total_time_taken
12 from(select starttime
13 , endtime
14 , total_time_taken
15 , (endtime - starttime) day(0) to second(0) as res
16 from t1
17 )
18 ;
Result:
STARTTIME ENDTIME TOTAL_TIME_TAKEN
----------- ----------- ----------------
02-12-2013 01:24:00 02-12-2013 04:17:00 02:53:00
Try this too,
WITH TIME AS (
SELECT to_date('02-12-2013 01:24:00', 'dd-mm-yyyy hh24:mi:ss') starttime,
to_date('02-12-2013 04:17:00', 'dd-mm-yyyy hh24:mi:ss') endTime
FROM dual)
SELECT to_char(TRUNC ((endTime - startTime)* 86400 / (60 * 60)), 'fm09')||':'||
to_char(TRUNC (MOD ((endTime - startTime)* 86400, (60*60)) / 60), 'fm09')||':'||
to_char(MOD((endTime - startTime)* 86400, 60), 'fm09') time_diff
FROM TIME;

Resources