Oracle PL/SQL get current timestamp number 19 - sql

Is there a way in Oralce PL/SQL to get the current timestamp as a NUMBER ?
Something like '1582185277302'

You can convert the current date/time to an epoch timestamp as follows:
(sysdate - date '1970-01-01') * 60 * 60 * 24
This gives you the number of seconds since January 1st, 1970.
If you want the results in milliseconds, then:
(cast(systimestamp as date) - date '1970-01-01') * 24 * 60 * 60 * 1000
+ mod( extract(second from systimestamp), 1) * 1000

Unix timestamps are in the UTC time zone. If your timestamp is in the UTC time zone then you can use:
( TRUNC( your_timestamp, 'MI' ) - DATE '1970-01-01' ) * 24 * 60 * 60 * 1000
+ EXTRACT( SECOND FROM your_timestamp ) * 1000
If your timestamps have a time zone then:
( TRUNC( your_timestamp AT TIME ZONE 'UTC', 'MI' ) - DATE '1970-01-01' ) * 24 * 60 * 60 * 1000
+ EXTRACT( SECOND FROM your_timestamp ) * 1000
If you need to handle leap seconds then you can use this answer.

If you subtract a fixed timestamp from systimestamp you get an interval:
select systimestamp - timestamp '1970-01-01 00:00:00 UTC' as diff
from dual;
DIFF
----------------------
+18312 10:05:29.674905
You can then extract and manipulate the elements of that to get the epoch time, using an inline view or CTE to avoid repeating the interval generation:
with t (diff) as (
select systimestamp - timestamp '1970-01-01 00:00:00 UTC'
from dual
)
select trunc(1000 * (
extract (day from diff) * 24 * 60 *60
+ extract (hour from diff) * 60 * 60
+ extract (minute from diff) * 60
+ extract (second from diff)
)) as epoch
from t;
EPOCH
-------------------
1582193129829
Adding all the extracts together gives you the total number of seconds, including fractions; multiplying by 1000 gives you milliseconds but will still have fractions (depending on the precision your platform supports); truncating that gives you just milliseconds.
This takes the time zone into account (epoch times are supposed to count from UTC); but doesn't allow for leap seconds.
As a further demo, using a fixed time in an arbitrary time zone to get the result in your question:
with t (diff) as (
select timestamp '2020-02-20 02:54:37.302789 America/New_York' - timestamp '1970-01-01 00:00:00 UTC'
from dual
)
select trunc(1000 * (
extract (day from diff) * 24 * 60 *60
+ extract (hour from diff) * 60 * 60
+ extract (minute from diff) * 60
+ extract (second from diff)
)) as epoch
from t;
EPOCH
-------------------
1582185277302

Related

Convert EPOCH date to timestamp in oracle SQL

I get a date format EPOCH in database table - "19072"
First I need to convert to time- 21/03/2022 and concatenate 23:59:59
date conversion reference - https://www.timeanddate.com/date/dateadded.html?d1=1&m1=1&y1=1970&type=add&ay=&am=&aw=&ad=19072&rec=
Now I need to convert "21/03/2022 23:59:59" to UTC +7:00(Jakarta, Indonesia)
Final expected output is - "22/03/2022 06:59:59"
You can add a number of days directly to a date:
select date '1970-01-01' + 19072 from dual;
21-MAR-22
or add an interval to a timestamp; which is probably more appropriate as you need to end up with a timestamp with time zone anyway, so this starts with a UTC value:
select timestamp '1970-01-01 00:00:00 UTC' + (19072 * interval '1' day) from dual;
21-MAR-22 00.00.00.000000000 PM UTC
Then you can add hours, minutes and seconds (or go ahead another day and subtract one second):
select
timestamp '1970-01-01 00:00:00 UTC'
+ (19072 * interval '1' day)
+ (23 * interval '1' hour)
+ (59 * interval '1' minute)
+ (59 * interval '1' second)
from dual;
21-MAR-22 11.59.59.000000000 PM UTC
and convert to your target time zone with at time zone:
select
(
timestamp '1970-01-01 00:00:00 UTC'
+ (19072 * interval '1' day)
+ (23 * interval '1' hour)
+ (59 * interval '1' minute)
+ (59 * interval '1' second)
)
at time zone 'Asia/Jakarta'
from dual;
22-MAR-22 06.59.59.000000000 AM ASIA/JAKARTA
and then for display purposes, convert to a string in the format you want:
select
to_char(
(
timestamp '1970-01-01 00:00:00 UTC'
+ (19072 * interval '1' day)
+ (23 * interval '1' hour)
+ (59 * interval '1' minute)
+ (59 * interval '1' second)
)
at time zone 'Asia/Jakarta',
'DD/MM/YYYY HH24:MI:SS'
) as result
from dual;
22/03/2022 06:59:59
You can simplify a bit by modifying your epoch, though it looks a bit odd:
select
to_char(
(
timestamp '1970-01-01 23:59:59 UTC'
+ (19072 * interval '1' day)
)
at time zone 'Asia/Jakarta',
'DD/MM/YYYY HH24:MI:SS'
) as result
from dual;
22/03/2022 06:59:59
(I'd probably prefer to keep the usual epoch and do the extra explicit interval additions...)
db<>fiddle
Only format as a string to display it. If you need to pass the value somewhere else then leave it as a timestamp with time zone, or if necessary cast that to a plain timestamp or even a date.

Today in Oracle Unix date

I have a field which stores the date in a Unix timestamp.
Instead of having to translate the test ie
TO_DATE( TO_CHAR( TO_DATE('19700101', 'yyyymmdd') + + ( FLOOR( ph.change_date / 24 / 60 / 60)))) = '07-NOV-2020'
I want to just say
ph.change_date = Todays Date
But have that as a Unix Timestamp.
Any help appreciated.
Unix time is in the UTC time zone; do not naively use SYSDATE as it may be in the wrong time zone. Use SYSTIMESTAMP and convert it to UTC:
WHERE ph.change_date >= ( TRUNC( SYSTIMESTAMP AT TIME ZONE 'UTC' ) - DATE '1970-01-01' ) * 24 *60 * 60
AND ph.change_date < ( TRUNC( ( SYSTIMESTAMP + INTERVAL '1' DAY ) AT TIME ZONE 'UTC' ) - DATE '1970-01-01' ) * 24 *60 * 60
I would suggest:
ts >= (trunc(sysdate) - date '1970-01-01') * 24 * 60 * 60 and
ts >= (trunc(sysdate) + 1 - date '1970-01-01') * 24 * 60 * 60
This is index-compatible, so it can make use of an index on ts.
If you don't care about that, this is an alternative:
trunc(date '1970-01-01' + ts * interval '1' second) = trunc(sysdate)

Is there any way I can convert VARCHAR2 to SECONDS?

My output is like this
**Column1** **Column2**
20170123012057.555 20170123070616.314
I should get 20719 seconds if I minus the two columns
You can convert the values to a date and then take the difference:
select (to_date(substr(column2, 1, 14), 'YYYYMMDDHH24MISS') -
to_date(substr(column1, 1, 14), 'YYYYMMDDHH24MISS')
) * 24 * 60 * 60
Try this. Here I have given difference in milliseconds as well as in seconds which is rounded
select
extract(day from (to_timestamp(column2,'YYYYMMDDHH24MISS.FF')
-to_timestamp(column1,'YYYYMMDDHH24MISS.FF')
)*86400*1000) / 1000
as diff_in_milliseconds
,round(extract(day from (to_timestamp(column2,'YYYYMMDDHH24MISS.FF')-
to_timestamp(column1,'YYYYMMDDHH24MISS.FF')
)*86400*1000) / 1000
) as diff_in_seconds
from
(select
'20170123012057.555' as Column1,
'20170123070616.314' as Column2
from dual)
Output
DIFF_IN_MILLISECONDS DIFF_IN_SECONDS
20718,7590 20719
Try as
SELECT ROUND (seconds / 1000) seconds
FROM (SELECT EXTRACT (DAY FROM cal_col) * 24 * 60 * 60 * 1000
+ EXTRACT (HOUR FROM cal_col) * 60 * 60 * 1000
+ EXTRACT (MINUTE FROM cal_col) * 60 * 1000
+ ROUND (EXTRACT (SECOND FROM cal_col) * 1000)
seconds
FROM (SELECT TO_TIMESTAMP ('20170123070616.314',
'YYYYMMDDHH24MISS.FF')
- TO_TIMESTAMP ('20170123012057.555',
'YYYYMMDDHH24MISS.FF')
cal_col
FROM DUAL))

PostgreSQL: how to convert from Unix epoch to date?

The statement gives me the date and time.
How could I modify the statement so that it returns only the date (and not the time)?
SELECT to_timestamp( TRUNC( CAST( epoch_ms AS bigint ) / 1000 ) );
You use to_timestamp function and then cast the timestamp to date
select to_timestamp(epoch_column)::date;
You can use more standard cast instead of ::
select cast(to_timestamp(epoch_column) as date);
More details:
/* Current time */
select now(); -- returns timestamp
/* Epoch from current time;
Epoch is number of seconds since 1970-01-01 00:00:00+00 */
select extract(epoch from now());
/* Get back time from epoch */
-- Option 1 - use to_timestamp function
select to_timestamp( extract(epoch from now()));
-- Option 2 - add seconds to 'epoch'
select timestamp with time zone 'epoch'
+ extract(epoch from now()) * interval '1 second';
/* Cast timestamp to date */
-- Based on Option 1
select to_timestamp(extract(epoch from now()))::date;
-- Based on Option 2
select (timestamp with time zone 'epoch'
+ extract(epoch from now()) * interval '1 second')::date;
In your case:
select to_timestamp(epoch_ms / 1000)::date;
PostgreSQL Docs
select to_timestamp(cast(epoch_ms/1000 as bigint))::date
worked for me
On Postgres 10:
SELECT to_timestamp(CAST(epoch_ms as bigint)/1000)
The solution above not working for the latest version on PostgreSQL. I found this way to convert epoch time being stored in number and int column type is on PostgreSQL 13:
SELECT TIMESTAMP 'epoch' + (<table>.field::int) * INTERVAL '1 second' as started_on from <table>;
For more detail explanation, you can see here https://www.yodiw.com/convert-epoch-time-to-timestamp-in-postgresql/#more-214
This works for me fine:
SELECT t.*,
to_timestamp(cast(t.prev_fire_time/1000 as bigint)) as prev_fire_time,
to_timestamp(cast(t.next_fire_time/1000 as bigint)) as next_fire_time,
to_timestamp(cast(t.start_time/1000 as bigint)) as start_time
FROM public.qrtz_triggers t;
Seconds since epoch with GNU date:
$ date +%s.%N
1627059870.945134901
This works with PostgreSQL 11:
# select to_timestamp (1627059870.945134901);
to_timestamp
-------------------------------
2021-07-23 19:04:30.945135+02
(1 row)
# select to_timestamp (1627059870.945134901)::date;
to_timestamp
--------------
2021-07-23
(1 row)

Extracting the total number of seconds from an interval data-type

When subtracting timestamps the return value is an interval data-type. Is there an elegant way to convert this value into the total number of (milli/micro) seconds in the interval, i.e. an integer.
The following would work, but it's not very pretty:
select abs( extract( second from interval_difference )
+ extract( minute from interval_difference ) * 60
+ extract( hour from interval_difference ) * 60 * 60
+ extract( day from interval_difference ) * 60 * 60 * 24
)
from ( select systimestamp - (systimestamp - 1) as interval_difference
from dual )
Is there a more elegant method in SQL or PL/SQL?
An easy way:
select extract(day from (ts1-ts2)*86400) from dual;
The idea is to convert the interval value into days by times 86400 (= 24*60*60).
Then extract the 'day' value which is actually second value we wanted.
I hope this help:
zep#dev> select interval_difference
2 ,sysdate + (interval_difference * 86400) - sysdate as fract_sec_difference
3 from (select systimestamp - (systimestamp - 1) as interval_difference
4 from dual)
5 ;
INTERVAL_DIFFERENCE FRACT_SEC_DIFFERENCE
------------------------------------------------------------------------------- --------------------
+000000001 00:00:00.375000 86400,375
With your test:
zep#dev> select interval_difference
2 ,abs(extract(second from interval_difference) +
3 extract(minute from interval_difference) * 60 +
4 extract(hour from interval_difference) * 60 * 60 +
5 extract(day from interval_difference) * 60 * 60 * 24) as your_sec_difference
6 ,sysdate + (interval_difference * 86400) - sysdate as fract_sec_difference
7 ,round(sysdate + (interval_difference * 86400) - sysdate) as sec_difference
8 ,round((sysdate + (interval_difference * 86400) - sysdate) * 1000) as millisec_difference
9 from (select systimestamp - (systimestamp - 1) as interval_difference
10 from dual)
11 /
INTERVAL_DIFFERENCE YOUR_SEC_DIFFERENCE FRACT_SEC_DIFFERENCE SEC_DIFFERENCE MILLISEC_DIFFERENCE
------------------------------------------------------------------------------- ------------------- -------------------- -------------- -------------------
+000000001 00:00:00.515000 86400,515 86400,515 86401 86400515
zep#dev>
I've found this to work. Apparently, if you do arithmetics with timestamps they are converted to some internal datatype that, when substracted from each other, returns the interval as a number.
Easy? Yes. Elegant? No. Gets the work done? Oh yeah.
SELECT ( (A + 0) - (B + 0) ) * 24 * 60 * 60
FROM
(
SELECT SYSTIMESTAMP A,
SYSTIMESTAMP - INTERVAL '1' MINUTE B
FROM DUAL
);
Unfortunately, I don't think that there is an alternative (or more elegant) way of calculating total seconds from an interval type in pl/sql. As this article mentions:
... unlike .NET, Oracle provides no simple equivalent to TimeSpan.TotalSeconds.
therefore extracting day, hour etc from the interval and multiplying them with corresponding values seems like the only way.
Based on zep's answer, I wrapped things up into a function for your convenience:
CREATE OR REPLACE FUNCTION intervalToSeconds(
pMinuend TIMESTAMP , pSubtrahend TIMESTAMP ) RETURN NUMBER IS
vDifference INTERVAL DAY TO SECOND ;
vSeconds NUMBER ;
BEGIN
vDifference := pMinuend - pSubtrahend ;
SELECT EXTRACT( DAY FROM vDifference ) * 86400
+ EXTRACT( HOUR FROM vDifference ) * 3600
+ EXTRACT( MINUTE FROM vDifference ) * 60
+ EXTRACT( SECOND FROM vDifference )
INTO
vSeconds
FROM DUAL ;
RETURN vSeconds ;
END intervalToSeconds ;
Use following query:
select (cast(timestamp1 as date)-cast(timestamp2 as date))*24*60*60)
Similar to #Zhaoping Lu answer but directly extracting seconds instead of getting them from the number of days.
SELECT extract(second from (end_date - start_date)) as "Seconds number"
FROM my_table
(worked on PostgresSQL 9.6.1)
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
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 a got the exception "ORA-01873: the leading precision of the interval is too smalll" when multiplying the interval by 86400, so I've decided do post the methods that works for me.
SELECT to_char(ENDTIME,'yyyymmddhh24missff')-to_char(STARTTIME,'yyyymmddhh24missff') AS DUR
FROM DUAL;
yyyymmddhh24miss- WILL GIVE DURATION IN SEC
yyyymmddhh24mi DURATION IN MIN
yyyymmddhh24 - DURATION - HOURS
yyyymmdd DURATION IN DAYS