I have an Oracle table called ACQDATA with a field READDATETIME where I store a Unix timestamp in milliseconds as an INTEGER (NUMBER(38)) type.
SQL> select READDATETIME from ACQDATA where ID=1000;
READDATETIME
____________
1.4793E+12
I need to select that value as a ISO-8601 string (YYYY-MM-DDTHH:MM:SS.mmm):
SQL> select READDATETIME from ACQDATA where ID=1000;
READDATETIME
-------------------
1.4793E+12
I´ve tried to convert it using TO_CHAR, but the result is messy:
SQL> select TO_CHAR(TO_DATE('1970-01-01','YYYY-MM-DD') + NUMTODSINTERVAL(READDATETIME, 'SECOND'), 'YYYY-MM-DD HH24:MI:SS') from ACQDATA where ID=1000;
Error at line 1:
ORA-01873: the leading precision of the interval is too small
Help appreciated.
Alex's answer is not fully correct. Unix timestamp is always based on 1970-01-01 00:00:00 UTC
Unless your session runs on UTC time zone the precise solution would be like this:
select
TO_CHAR((TIMESTAMP '1970-01-01 00:00:00 UTC' + readdatetime/1000 * INTERVAL '1' SECOND) AT LOCAL, 'YYYY-MM-DD"T"HH24:MI:SS.FF3')
from ACQDATA where ID=1000;
or
select
TO_CHAR((TIMESTAMP '1970-01-01 00:00:00' AT TIME ZONE 'UTC' + readdatetime/1000 * INTERVAL '1' SECOND) AT LOCAL, 'YYYY-MM-DD"T"HH24:MI:SS.FF3')
from ACQDATA where ID=1000;
or if you prefer functions instead of literals:
select
TO_CHAR((TO_TIMESTAMP_TZ('1970-01-01 00:00:00 UTC', 'YYYY-MM-DD HH24:MI:SS TZR') + numtodsinterval(readdatetime/1000, 'SECOND')) AT LOCAL, 'YYYY-MM-DD"T"HH24:MI:SS.FF3')
from ACQDATA where ID=1000;
Your readdatetime seems to be in milliseconds. Oracle date arithmetic works on the basis of days, so you need to convert that number to the number of days it represents; one day is 86400 seconds, so it's 86400000 milliseconds:
with acqdata (id, readdatetime) as (
select 1000, 1479318995000 from dual
)
select to_char(date '1970-01-01' + (READDATETIME/86400000), 'YYYY-MM-DD"T"HH24:MI:SS')
from ACQDATA where ID=1000;
TO_CHAR(DATE'1970-0
-------------------
2016-11-16T17:56:35
The T is added as a character literal.
SQL Developer defaults to show numbers that large in scientific notation. You can change that default with set numformat, or use to_char() to show the whole value:
select readdatetime, to_char(readdatetime, '9999999999999') as string
from ACQDATA where ID=1000;
READDATETIME STRING
------------ --------------
1.4793E+12 1479318995000
If your value has fractional seconds, so the last three digits are not zeros, you can convert the date to a timestamp and add on the fractional leftovers; this also adds the UTC 'Z' indicator for fun:
with acqdata (id, readdatetime) as (
select 1000, 1479300462063 from dual
)
select to_char(cast(date '1970-01-01' + (readdatetime/86400000) as timestamp)
+ numtodsinterval(remainder(readdatetime, 1000)/1000, 'SECOND'),
'YYYY-MM-DD"T"HH24:MI:SS.FF3"Z"')
from acqdata where id=1000;
TO_CHAR(CAST(DATE'1970-01-01'+
------------------------------
2016-11-16T12:47:42.063Z
Or without the intermediate date value, starting from a timestamp literal:
with acqdata (id, readdatetime) as (
select 1000, 1479300462063 from dual
)
select to_char(timestamp '1970-01-01 00:00:00'
+ numtodsinterval(readdatetime/1000, 'SECOND'),
'YYYY-MM-DD"T"HH24:MI:SS.FF3"Z"')
from acqdata where id=1000;
TO_CHAR(TIMESTAMP'1970-0
------------------------
2016-11-16T12:47:42.063Z
As #Wernfried ponted out, it's better to explicitly show that the epoch time is starting from UTC:
alter session set time_zone='America/New_York';
with acqdata (readdatetime) as (
select 1479300462063 from dual
union all select 1467331200000 from dual
union all select 1467648000000 from dual
)
select readdatetime,
to_char(timestamp '1970-01-01 00:00:00' + numtodsinterval(readdatetime/1000, 'SECOND'),
'YYYY-MM-DD"T"HH24:MI:SS.FF3') as implicit,
to_char(cast(timestamp '1970-01-01 00:00:00' as timestamp with time zone)
+ numtodsinterval(readdatetime/1000, 'SECOND'),
'YYYY-MM-DD"T"HH24:MI:SS.FF3TZH:TZM') as local_offset,
to_char(timestamp '1970-01-01 00:00:00 UTC' + numtodsinterval(readdatetime/1000, 'SECOND'),
'YYYY-MM-DD"T"HH24:MI:SS.FF3TZH:TZM') as utc_offset,
to_char(timestamp '1970-01-01 00:00:00 UTC' + numtodsinterval(readdatetime/1000, 'SECOND'),
'YYYY-MM-DD"T"HH24:MI:SS.FF3TZR') as utc
from acqdata;
READDATETIME IMPLICIT LOCAL_OFFSET UTC_OFFSET UTC
-------------- ----------------------- ----------------------------- ----------------------------- --------------------------
1479300462063 2016-11-16T12:47:42.063 2016-11-16T12:47:42.063-05:00 2016-11-16T12:47:42.063+00:00 2016-11-16T12:47:42.063UTC
1467331200000 2016-07-01T00:00:00.000 2016-07-01T01:00:00.000-04:00 2016-07-01T00:00:00.000+00:00 2016-07-01T00:00:00.000UTC
1467648000000 2016-07-04T16:00:00.000 2016-07-04T17:00:00.000-04:00 2016-07-04T16:00:00.000+00:00 2016-07-04T16:00:00.000UTC
Related
I want to convert the epoch date from table into timestamp.
But it results in an error when I run it in Oracle.
But the year showing into "Rabu, 22 April 2465 pukul 15.35.06.289 GMT+07:00" when i run from this link "https://www.epochconverter.com/'
15630394456289509085900
this the epoch time from table
select to_char(
cast(
to_date('01/01/1970 00:00:00','DD/MM/YYYY HH24:MI:SS')+15630394456289509085900/86400
as timestamp with local time zone)
,'YYYY-MM-DD HH24:MI:SS')
from dual
Epoch times are in the UTC time zone. Just use a TIMESTAMP literal and add the correct amount of seconds:
SELECT TIMESTAMP '1970-01-01 00:00:00 UTC'
+ NUMTODSINTERVAL(15630394456289509085900 / 86400e12, 'DAY') AS epoch_time_12,
TIMESTAMP '1970-01-01 00:00:00 UTC'
+ NUMTODSINTERVAL(15630394456289509085900 / 86400e13, 'DAY') AS epoch_time_13
FROM DUAL
Which outputs:
EPOCH_TIME_12 | EPOCH_TIME_13
:-------------------------------- | :--------------------------------
2465-04-22 08:14:16.289509086 UTC | 2019-07-13 17:37:25.628950909 UTC
db<>fiddle here
I currently have a SQL query that returns the correct local DATETIME from a Unix TIMESTAMP column in our DB.
Here is an example using a specific TIMESTAMP of 1539961967000:
SELECT FROM_TZ(CAST(DATE '1970-01-01' + 1539961967000 * (1/24/60/60/1000) AS TIMESTAMP), 'UTC') AT TIME ZONE 'America/Denver' DATETIME
FROM dual;
which returns:
DATETIME
19-OCT-18 09.12.47.000000000 AM AMERICA/DENVER
I am having a hard time reversing this query to return a Unix TIMESTAMP starting with a local DATETIME.
Has anyone ever encountered this before?
You can convert your timestamp with timezone to UTC, and then subtract the epoch from that:
select timestamp '2018-10-19 09:12:47.0 AMERICA/DENVER'
- timestamp '1970-01-01 00:00:00.0 UTC' as diff
from dual;
which gives you an interval data type:
DIFF
----------------------
+17823 15:12:47.000000
You can then extract the elements from that, and multiply each element by an appropriate factor to convert it to milliseconds (i.e. for days, 60*60*24*1000); and then add them together:
select extract(day from diff) * 86400000
+ extract(hour from diff) * 3600000
+ extract(minute from diff) * 60000
+ extract(second from diff) * 1000 as unixtime
from (
select timestamp '2018-10-19 09:12:47.0 AMERICA/DENVER'
- timestamp '1970-01-01 00:00:00.0 UTC' as diff
from dual
);
UNIXTIME
--------------------
1539961967000
db<>fiddle
This preserves milliseconds too, if the starting timestamp has them (this converts from a 'Unix' time while preserving them):
select (timestamp '1970-01-01 00:00:00.0 UTC' + (1539961967567 * interval '0.001' second))
at time zone 'America/Denver' as denver_time
from dual;
DENVER_TIME
--------------------------------------------
2018-10-19 09:12:47.567000000 AMERICA/DENVER
then to convert back:
select extract(day from diff) * 86400000
+ extract(hour from diff) * 3600000
+ extract(minute from diff) * 60000
+ extract(second from diff) * 1000 as unixtime
from (
select timestamp '2018-10-19 09:12:47.567 AMERICA/DENVER'
- timestamp '1970-01-01 00:00:00.0 UTC' as diff
from dual
);
UNIXTIME
--------------------
1539961967567
db<>fiddle
If your starting timestamp has greater precision than that then you'll need to truncate (or round/floor/ceil/cast) to avoid having a non-integer result; this version just truncates the extracted milliseconds part:
select diff,
extract(day from diff) * 86400000
+ extract(hour from diff) * 3600000
+ extract(minute from diff) * 60000
+ trunc(extract(second from diff) * 1000) as unixtime
from (
select timestamp '2018-10-19 09:12:47.123456789 AMERICA/DENVER'
- timestamp '1970-01-01 00:00:00.0 UTC' as diff
from dual
);
DIFF UNIXTIME
------------------------- --------------------
+17823 15:12:47.123456789 1539961967123
Without that truncation (or equivalent) you'd end up with 1539961967123.456789.
I'd forgotten about the leap seconds discrepancy; if you need/want to handle that, see this answer.
The main issue is that Oracle has two ways (at least) to convert a number of seconds to an interval day-to-second - either with a function or with a simple arithmetic operation on an interval literal - but no direct way to do the reverse.
In the two queries below, first I show how to convert a UNIX timestamp (in milliseconds since the Epoch) to an Oracle timestamp, without losing milliseconds. (See my comment under your Question, where I point out that your method will lose milliseconds.) Then I show how to reverse the process.
Like you, I ignore the difference between "timestamp at UTC" and "Unix timestamp" caused by "Unix timestamp" ignoring leap seconds. Your business must determine whether that is important.
Unix timestamp to Oracle timestamp with time zone (preserving milliseconds):
with
inputs (unix_timestamp) as (
select 1539961967186 from dual
)
select from_tz(timestamp '1970-01-01 00:00:00'
+ interval '1' second * (unix_timestamp/1000), 'UTC')
at time zone 'America/Denver' as oracle_ts_with_timezone
from inputs
;
ORACLE_TS_WITH_TIMEZONE
--------------------------------------
2018-10-19 09:12:47.186 America/Denver
Oracle timestamp with time zone to Unix timestamp (preserving milliseconds):
with
sample_data (oracle_ts_with_timezone) as (
select to_timestamp_tz('2018-10-19 09:12:47.186 America/Denver',
'yyyy-mm-dd hh24:mi:ss.ff tzr') from dual
)
select ( extract(second from ts)
+ (trunc(ts, 'mi') - date '1970-01-01') * (24 * 60 * 60)
) * 1000 as unix_timestamp
from ( select cast(oracle_ts_with_timezone at time zone 'UTC'
as timestamp) as ts
from sample_data
)
;
UNIX_TIMESTAMP
----------------
1539961967186
I tried to execute the below query but it's throwing me error :
SELECT TO_DATE(
TIMESTAMP '1970-01-01 00:00:00' + numtodsinterval(1511421211, 'second')
,'DD-MM-YYYY HH24:MI:SS')
FROM dual
Error : ORA-01830: date format picture ends before converting entire input string
The TO_DATE( datestring, format_model ) function takes strings as arguments.
Your query:
SELECT TO_DATE(
TIMESTAMP '1970-01-01 00:00:00' + numtodsinterval(1511421211, 'second')
,'DD-MM-YYYY HH24:MI:SS'
)
FROM dual
Is passing a TIMESTAMP and a string so Oracle has to perform an implicit conversion from TIMESTAMP to a string so your function is effectively:
SELECT TO_DATE(
TO_CHAR(
TIMESTAMP '1970-01-01 00:00:00' + numtodsinterval(1511421211, 'second'),
(
SELECT value
FROM NLS_SESSION_PARAMETERS
WHERE parameter = 'NLS_TIMESTAMP_FORMAT'
)
),
'DD-MM-YYYY HH24:MI:SS'
)
FROM dual
If the NLS_TIMESTAMP_FORMAT session paramter does not match your format model 'DD-MM-YYYY HH24:MI:SS' then an exception will be raised.
You could change the NLS_TIMESTAMP_FORMAT parameter - but this is a session parameter that is set per user and each user can change it at any time during their session so this should NOT be the solution.
Instead, you can just use a DATE literal instead of a TIMESTAMP literal:
SELECT DATE '1970-01-01' + NUMTODSINTERVAL (1511421211, 'second')
FROM DUAL
Or, if you want to use a timestamp then you can use the CAST function:
SELECT CAST(
TIMESTAMP '1970-01-01 00:00:00' + NUMTODSINTERVAL (1511421211, 'second')
AS DATE
)
FROM DUAL
Is this what you are expecting?
select to_char(DATE '1970-01-01' + NUMTODSINTERVAL (1511421211, 'second'), 'yyyy/mm/dd hh24:mi:ss') from dual;
The syntax appear somewhat incorrect to me. Try this:
SELECT TO_DATE ('1970-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS')
+ NUMTODSINTERVAL (1511421211, 'second')
FROM DUAL;
Edit:
As #a_horse.. said "Oracle DATE always contains a time",so if timestamp is not visible then you just need to see your NLS_DATE_FORMAT in table V$NLS_PARAMETERS. In your case its simply set to
NLS_DATE_FORMAT = 'DD-MM-YYYY';
So you need to alter the session first to get the timestamp in SQLPLUS. See below:
SQL> alter session set NLS_DATE_FORMAT = 'mm-dd-yyyy HH24:mi:ss';
Session altered.
SQL> SELECT TO_DATE ('1970-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS') + NUMTODSINTERVAL (15114212
11, 'second') FROM DUAL;
TO_DATE('1970-01-01
-------------------
11-23-2017 07:13:31
I have simple calculation, I subtract interval from date with time:
select TO_DATE('2016-12-05 23:04:59', 'YYYY-MM-DD HH24:MI:SS') - to_dsinterval('00 0:05:00') from dual;
It works fine, the result: 2016-12-05 22:59:59
but it doesn't work correctly with timezones, so the next approach solves the problem with timezone. I just wrap expression with to_date() one more time
select TO_DATE(
TO_DATE('2016-12-05 23:04:59', 'YYYY-MM-DD HH24:MI:SS') - to_dsinterval('00 0:05:00')) from dual;
but now it turns time to zeros. Result should be: 2016-12-05 22:59:59 but actual: 2016-12-05 00:00:00
If I add format to the outer to_date as this:
select to_date( TO_DATE('2016-12-05 23:04:59', 'YYYY-MM-DD HH24:MI:SS') - to_dsinterval('00 0:05:00'), 'YYYY-MM-DD HH24:MI:SS') from dual;
The result become very strange: 0005-12-16 00:00:00
What I'm doing wrong?
DATE data type does not support any time zone functions, you must use TIMESTAMP WITH TIME ZONE for that.
Your query
SELECT TO_DATE( TO_DATE('2016-12-05 23:04:59', 'YYYY-MM-DD HH24:MI:SS') - TO_DSINTERVAL('00 0:05:00'), 'YYYY-MM-DD HH24:MI:SS')
FROM dual;
does following:
Create a DATE '2016-12-05 23:04:59'
Subtract interval '00 0:05:00'
Cast to a VARCHAR2 (using NLS_DATE_FORMAT format)
Cast to a DATE using YYYY-MM-DD HH24:MI:SS format
In case your NLS_DATE_FORMAT would be equal to YYYY-MM-DD HH24:MI:SS this query returns correct output.
Use this one:
SELECT TO_TIMESTAMP('2016-12-05 23:04:59', 'YYYY-MM-DD HH24:MI:SS') - TO_DSINTERVAL('00 0:05:00')
FROM dual;
TO_DATE(... works as well. If you need time zone support you must do:
SELECT TO_TIMESTAMP_TZ('2016-12-05 23:04:59 Europe/Berlin', 'YYYY-MM-DD HH24:MI:SS TZR') - TO_DSINTERVAL('00 0:05:00')
FROM dual;
TO_DATE( char, fmt, nls ) takes VARCHAR2 arguments.
Performing TO_DATE('2016-12-05 23:04:59', 'YYYY-MM-DD HH24:MI:SS') - to_dsinterval('00 0:05:00') returns a DATE datatype which when you pass it to TO_DATE() oracle will cast it to a VARCHAR2 datatype so it matches the expected datatype of the argument (implicitly calling TO_CHAR( value, NLS_DATE_FORMAT ) to perform this cast) and then convert this back to a DATE datatype.
You just need to do:
SELECT TO_DATE('2016-12-05 23:04:59', 'YYYY-MM-DD HH24:MI:SS')
- to_dsinterval('00 0:05:00')
FROM DUAL;
If you want to handle time zones then use a TIMESTAMP AT TIME ZONE and just convert it to whatever timezone you want to store the date at:
SELECT TIMESTAMP '2016-12-05 23:04:59 Europe/Paris' AT TIME ZONE 'UTC'
FROM DUAL;
(Will create your timestamp in Paris' time zone and convert it to the correct time in the UTC time zone).
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.