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)
Related
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.
Hi dear I have a table with columns DT, DT2, DT3, DT4 I can insert in one column but not at all column same time please if you have any idea then told me thanks in advance my code is
insert into calendar_dateS4 (DT,DT2,DT3, DT4, DT5 )
SELECT DT, DT2, DT3, DT4, DT5
FROM (
SELECT DATE '2020-01-01' + FLOOR( (LEVEL - 1) )
+ INTERVAL '08:45' HOUR TO MINUTE
+ DBMS_RANDOM.VALUE() * INTERVAL '00:15' HOUR TO MINUTE
+ INTERVAL '16:45' HOUR TO MINUTE
+ DBMS_RANDOM.VALUE() * INTERVAL '00:15' HOUR TO MINUTE
+ INTERVAL '05:45' HOUR TO MINUTE
+ DBMS_RANDOM.VALUE() * INTERVAL '00:15' HOUR TO MINUTE
+ INTERVAL '13:45' HOUR TO MINUTE
+ DBMS_RANDOM.VALUE() * INTERVAL '00:15' HOUR TO MINUTE
+ INTERVAL '21:45' HOUR TO MINUTE
+ DBMS_RANDOM.VALUE() * INTERVAL '00:15' HOUR TO MINUTE
AS DT, DT2, DT3, DT4, DT5
FROM DUAL
CONNECT BY
DATE '2020-01-01' + FLOOR( (LEVEL - 1) )
< ADD_MONTHS( DATE '2020-01-01', 12 )
)
Your INSERT is failing because your SELECT statement is not valid. Work on getting a valid SELECT statement with the results you want, then convert that into an INSERT statement.
To insert the same time into all 5 columns, you can use a statement like this:
INSERT INTO calendar_dateS4 (DT,
DT2,
DT3,
DT4,
DT5)
SELECT dt,
dt,
dt,
dt,
dt
FROM ( SELECT DATE '2020-01-01'
+ FLOOR ((LEVEL - 1))
+ INTERVAL '08:45' HOUR TO MINUTE
+ DBMS_RANDOM.VALUE () * INTERVAL '00:15' HOUR TO MINUTE
+ INTERVAL '16:45' HOUR TO MINUTE
+ DBMS_RANDOM.VALUE () * INTERVAL '00:15' HOUR TO MINUTE
+ INTERVAL '05:45' HOUR TO MINUTE
+ DBMS_RANDOM.VALUE () * INTERVAL '00:15' HOUR TO MINUTE
+ INTERVAL '13:45' HOUR TO MINUTE
+ DBMS_RANDOM.VALUE () * INTERVAL '00:15' HOUR TO MINUTE
+ INTERVAL '21:45' HOUR TO MINUTE
+ DBMS_RANDOM.VALUE () * INTERVAL '00:15' HOUR TO MINUTE AS DT
FROM DUAL
CONNECT BY DATE '2020-01-01' + FLOOR ((LEVEL - 1)) < ADD_MONTHS (DATE '2020-01-01', 12))
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
My Sample Table looks like this ..
Primary_Key || Start_Time || End_Time || Value
1 || 24-FEB-13 18:00:00 || 24-FEB-13 19:00:00 || 6
The data types of these columns are
Primary_Key -- Int
Start_Time --- TimeStamp
End_Time --- TimeStamp
Value --- Int
Now , i want to fetch all the records in the table which have the End_Time value within the 60 mins of the current time ?
Try this...
SELECT * FROM yourTable
WHERE end_time >= CURRENT_TIMESTAMP - NUMToDSInterval(1, 'HOUR')
That should work with DATE and TIMESTAMP and TIMESTAMP WITH TIME ZONE values.
This should work:
select *
from sample s
where CURRENT_TIMESTAMP - end_time <= 1/24.0 and CURRENT_TIMESTAMP >= end_time
Try this
select * from yourtable
WHERE (sysdate - End_Time) * 1440 between 0 and 60
You may try this - select your data between your_start_date and your_start_date + INTERVAL '60' MINUTE:
SELECT SYSDATE start_dt, (SYSDATE + INTERVAL '60' MINUTE) end_dt
FROM dual
/
SELECT * FROM
(
SELECT to_date('24-FEB-13 18:00:00', 'DD-MON-YYYY HH24:MI:SS') your_start_date
,(to_date('24-FEB-13 18:00:00', 'DD-MON-YYYY HH24:MI:SS') + INTERVAL '60' MINUTE) your_end_dt
FROM dual
)
/
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