Oracle sql how to get start and end dates of weeks between two dates - oracle

I want to get the start and end days of every week between two dates. The dates's format is dd/mm/yyy hh24:mi:ss. I need the weeks in the format dd/mm/yyyy hh24:mi:ss because I have to calculate the days and hours between the start and end day of the week with the times
I wrote this statement
WITH
date_range AS (
SELECT
pdm.des_comercial serie,
pdm.id_material codserie,
ri.id_accion intervencion,
TO_CHAR(NVL(ri.fecha_salida_rev, SYSDATE), 'dd/mm/RRRR') fecha1,
to_char((CASE
WHEN ri.fecha_salida_rev > TO_DATE('18/06/2019', 'dd/mm/yyyy') THEN TO_DATE('18/06/2019', 'dd/mm/yyyy')
WHEN ri.fecha_salida_Rev IS NULL THEN TO_DATE('18/06/2019', 'dd/mm/yyyy')
ELSE ri.fecha_salida_Rev
END),'dd/mm/yyyy hh24:mi:ss') fechasalida,
to_char((CASE
WHEN ri.fecha_entrada_rev < TO_DATE('01/06/2019', 'dd/mm/yyyy') THEN TO_DATE('01/06/2019', 'dd/mm/yyyy')
ELSE ri.fecha_entrada_Rev
END),'dd/mm/yyyy hh24:mi:ss') fechaentrada
,
ri.cod_taller_rev,
ri.COD_MATRICULA,
ri.fecha_entrada_rev start_date,
ri.fecha_salida_rev end_date
FROM
r_intervencion ri,
planificador.pl_dh_material pdm
WHERE
ri.id_accion = ri.amortizada_por
AND ri.causa_entrada = 1
AND ri.tipo_accion = 1
AND pdm.id_material = ri.cod_serie
AND pdm.hasta = 99999999
AND ri.ID_ACCION = 'IM4'
AND ri.fecha_salida_rev BETWEEN TO_DATE('01/06/2019', 'dd/mm/yyyy') AND TO_DATE('18/06/2019', 'dd/mm/yyyy')
),
semanas AS (
SELECT LEVEL "Week"
,to_char(to_date(start_date,'dd/mm/yyyy hh24:mi:ss') + (7 * (LEVEL - 1)),'IW') startweek
,to_char(to_date(start_date ,'dd/mm/yyyy hh24:mi:ss')+ (7 * (LEVEL - 1)),'IW') + 6 endweek
,TO_CHAR(start_date + (7 * (LEVEL - 1)),'IW') "Iso Week",
serie,
codserie,
intervencion,
cod_taller_rev,
cod_matricula,
fechaentrada,
fechasalida,
start_date,
end_date
FROM date_range
CONNECT BY LEVEL <= (to_char(To_date(end_date,'dd/mm/yyyy hh24:mi:ss'),'IW') - to_char(To_date(start_date,'dd/mm/yyyy hh24:mi:ss'),'IW')) / 7 + 1
)
SELECT startweek,
endweek,
to_date(endweek,'dd/mm/yyyy hh24:mi:ss') - to_date(startweek,'dd/mm/yyyy hh24:mi:ss') dias,
serie,
codserie,
intervencion,
cod_taller_rev,
cod_matricula,
start_Date,
end_date,
fechaentrada,
fechasalida,
rd.descripcion
FROM semanas,r_depositos rd
WHERE cod_taller_rev = rd.cod_deposito
When I execute it, I get
Query execution failed
SQL Error [1840] [22008]: ORA-01840: ORA-01840: input value not long enough for date format
The error is in
,to_char(to_date(start_date,'dd/mm/yyyy hh24:mi:ss') + (7 * (LEVEL - 1)),'IW') startweek
,to_char(to_date(start_date ,'dd/mm/yyyy hh24:mi:ss')+ (7 * (LEVEL - 1)),'IW') + 6 endweek
How can I get the startweek and endweek with the format dd/mm/yyyy hh24:mi:ss
EDITED
start_date end_date
20/05/2019 20:00:00 05/06/2019 08:00:00
weeks
20/05/2019 20:00:00 26/05/2019 -> 6 days and xxx hours
27/05/2019 02/06/2019 -> 7 days
03/06/2019 05/06/2019 08:00:00 -> 3 days and xxx hours
I need to calculate the difference in days and hours for each week.
For example between 20/05/2019 20:00:00 and 26/05/2019
and last one between 03/06/2019 and 05/06/2019 08:00:00
My issue is with the calculation
to_date(endweek,'dd/mm/yyyy hh24:mi:ss') - to_date(startweek,'dd/mm/yyyy hh24:mi:ss') dias,
endweek and startweek have to have dd/mm/yyyy hh24:mi:ss

My issue is with the calculation
to_date(endweek,'dd/mm/yyyy hh24:mi:ss') - to_date(startweek,'dd/mm/yyyy hh24:mi:ss') dias,
endweek and startweek have to have dd/mm/yyyy hh24:mi:ss
Oracle dates are stored in an internal format which you generally don't need to worry about. Your application or client formats the date as a string, based on its own setting or your session NLS settings.
When you do something like:
to_date(endweek,'dd/mm/yyyy hh24:mi:ss')
you're really doing:
to_date(to_char(endweek),'dd/mm/yyyy hh24:mi:ss')
and as there is no explicit format mask specified for the implicit to_char() call it used your current session's NLS settings. Depending on the setting it might error; or might corrupt the value - e.g. mixing YY and YYYY masks can lose the century, converting 2019 to 0019. (Given the error you are getting, your NLS settings might be unusual?).
At best you're converting the date value to a string and back to exactly the same date value, which is pointless. You aren't changing the format of the datem because it doesn't have one. The intermediate string does, but you aren't using that, and you can't for calculations (at least without converting back to a date as you are, which again is pointless.)
Oracle has other functions to manipulate date values, including trunc(), so I think you might want something like this - showing the difference in three ways, though there are others and you can format the last one however you want:
with date_range (start_date, end_date) as (
-- dummy data from your example
select to_date('20/05/2019 20:00:00', 'DD/MM/YYYY HH24;MI:SS') as start_date,
to_date('05/06/2019 08:00:00', 'DD/MM/YYYY HH24;MI:SS') as end_date
from dual
),
semanas as (
select level as week,
start_date,
end_date,
greatest(trunc(start_date + (7 * (level - 1)), 'IW'), start_date) as start_week,
least(trunc(start_date + (7 * level), 'IW'), end_date) as end_week
from date_range
connect by level <= (trunc(end_date, 'IW') - trunc(start_date, 'IW')) / 7 + 1
)
select week,
to_char(start_week, 'IW') as iso_week,
to_char(start_week, 'DD/MM/YYYY HH24:MI:SS') as start_week,
to_char(end_week, 'DD/MM/YYYY HH24:MI:SS') as end_week,
end_week - start_week as diff_num,
numtodsinterval(end_week - start_week, 'DAY') as diff_interval,
to_char(date '1999-12-31' + (end_week - start_week), 'FMDD "days" HH24 "hours"') as diff_words
from semanas;
WEEK IS START_WEEK END_WEEK DIFF_NUM DIFF_INTERVAL DIFF_WORDS
---------- -- ------------------- ------------------- ---------- ------------------- ----------------
1 21 20/05/2019 20:00:00 27/05/2019 00:00:00 6.16666667 +06 04:00:00.000000 6 days 4 hours
2 22 27/05/2019 00:00:00 03/06/2019 00:00:00 7 +07 00:00:00.000000 7 days 0 hours
3 23 03/06/2019 00:00:00 05/06/2019 08:00:00 2.33333333 +02 08:00:00.000000 2 days 8 hours
As currently written the connect by only works properly if the date_range CTE generates a single value; if you actually get multiple rows back from your real query then you'll have to do a bit more work, or switch to recursive CTEs, or cross join/apply, depending on your Oracle version.

Your endweek calculation is
to_char(to_date(start_date ,'dd/mm/yyyy hh24:mi:ss')+ (7 * (LEVEL - 1)),'IW') + 6 endweek
This attempts to add the number 6 to a character string. I suspect that what you wanted was
to_char(to_date(start_date ,'dd/mm/yyyy hh24:mi:ss') + (7 * (LEVEL - 1) + 6),'IW') endweek
Here I've moved the + 6 so you're adding 6 to the date value, rather than to a character string.

Related

How to calculate the difference of HH:MM:SS between two dates in oracle sql?

I have a table abc as:
-- start_time |end_time | total_time_taken
-- 27.05.2020 00:52:48 |27.05.2020 02:08:33 |
I want to set the value of total_time_taken as the difference of end_time-start_time. in the format "HH:MM:SS".I searched the similar topic but didnot find the exact answer.
My expected output is like : 01:44:12 (HH:MM:SS)
So,i tried :
SELECT To_Char(end_time,'HH24:MM:SS'),To_Char(start_time,'HH24:MM:SS'),
To_Char(end_time,'HH24:MM:SS')-To_Char(start_time,'HH24:MM:SS') FROM abc;
The datatypes of start_time,end_time,total_time_taken is DATE.Please help me to find the solution.
If you cast those dates as timestamps, you can easily subtract them and see relatively nice result:
SQL> with test (st, et) as
2 (select to_date('27.05.2020 00:52:48', 'dd.mm.yyyy hh24:mi:ss'),
3 to_date('27.05.2020 02:08:33', 'dd.mm.yyyy hh24:mi:ss')
4 from dual
5 )
6 select cast(et as timestamp) - cast(st as timestamp) diff
7 from test;
DIFF
--------------------------------------------------------------------------
+000000000 01:15:45.000000
SQL>
If you want to format it as you wanted (note that mm format mask is for months; mi is for minutes), then you could do some extracting - again from timestamp (won't work for date):
SQL> with test (st, et) as
2 (select to_date('27.05.2020 00:52:48', 'dd.mm.yyyy hh24:mi:ss'),
3 to_date('27.05.2020 02:08:33', 'dd.mm.yyyy hh24:mi:ss')
4 from dual
5 ),
6 diff as
7 (select cast(et as timestamp) - cast(st as timestamp) diff
8 from test
9 )
10 select extract(hour from diff) ||':'||
11 extract(minute from diff) ||':'||
12 extract(second from diff) diff
13 from diff;
DIFF
-------------------------------------------------------------------------
1:15:45
SQL>
You can further make it pretty (e.g. two digits for hours, using LPAD function). Or, you can even write your own function which will actually work on difference of DATE datatype values, do some calculations (using trunc function, subtractions, whatnot), but the above looks pretty elegant if compared to a home-made function.
The answer by Littlefoot is perfectly fine. This answer is just to show there is more than one way to get the result.
First, we can subtract one date from another and get the difference in days, then convert that difference to an interval.
with test (st, et) as
(select to_date('27.05.2020 00:52:48', 'dd.mm.yyyy hh24:mi:ss'),
to_date('27.05.2020 02:08:33', 'dd.mm.yyyy hh24:mi:ss')
from dual
)
select numtodsinterval(et-st, 'day') diff
from test;
Then, since we can't control interval formatting directly, we can add DIFF to an arbitrary date and then use built-in date formatting.
with test (st, et) as
(select to_date('27.05.2020 00:52:48', 'dd.mm.yyyy hh24:mi:ss'),
to_date('27.05.2020 02:08:33', 'dd.mm.yyyy hh24:mi:ss')
from dual
)
select to_char(date '1-1-1' + numtodsinterval(et-st, 'day'), 'hh24:mi:ss') diff
from test;
DIFF
--------
01:15:45

date format picture ends before converting entire input string in Oracle

I have a PD_HEAT_DATA table with HEATID and HEATDEPARTURE_ACT columns. Data type of HEATDEPARTURE column is VARCHAR2 and it holds timestamps in the format 2019-07-28 23:11:11,359.
My requirement is to retrieve the records from PD_HEAT_DATA table between 6 AM of today and 6 AM of next day.
Sample Data:
HeatID HEATDEPARTURE_ACT
0001024002 2019-07-29 00:46:42,115
0001024003 2019-07-29 06:46:42,115
0001024004 2019-07-29 23:46:42,115
0001024003 2019-07-30 00:06:42,115
0001024004 2019-07-30 04:46:42,115
I have tried following code but it is not giving desired result:
select heatid, HEATDEPARTURE_ACT from hd_heat_data where to_date(HEATDEPARTURE_ACT, 'YYYY-MM-DD HH24:MI:SS') >= trunc(sysdate
-1) + 6/24 and
to_date(HEATDEPARTURE_ACT, 'YYYY-MM-DD HH24:MI:SS') < trunc(sysdate) + 6/24
I have tried following code but it is not giving desired result:
select heatid, HEATDEPARTURE_ACT from hd_heat_data where to_date(HEATDEPARTURE_ACT, 'YYYY-MM-DD HH24:MI:SS') >= trunc(sysdate
-1) + 6/24 and
to_date(HEATDEPARTURE_ACT, 'YYYY-MM-DD HH24:MI:SS') < trunc(sysdate) + 6/24
You have fractional seconds at the end of your HEATDEPARTURE_ACT strings which you need to trim off prior to converting the string to a date:
select heatid, HEATDEPARTURE_ACT
from hd_heat_data
where TO_DATE(REGEXP_SUBSTR(HEATDEPARTURE_ACT, '[^,]*'),
'YYYY-MM-DD HH24:MI:SS') BETWEEN trunc(sysdate-1) + INTERVAL '6' HOUR
AND trunc(sysdate) + INTERVAL '6' HOUR - INTERVAL '1' SECOND
dbfiddle here
(Note that I altered the dates in the fiddle data so results would be produced)
You need to change your format provided in TO_TIMESTAMP as TO_TIMESTAMP(HEATDEPARTURE_ACT, 'YYYY-MM-DD HH24:MI:SS,FF')
SELECT
HEATID,
HEATDEPARTURE_ACT
FROM
HD_HEAT_DATA
WHERE
TO_TIMESTAMP(HEATDEPARTURE_ACT, 'YYYY-MM-DD HH24:MI:SS,FF')
BETWEEN TRUNC(SYSDATE - 1) + INTERVAL '6' HOUR AND TRUNC(SYSDATE) +
INTERVAL '6' HOUR - INTERVAL '1' SECOND
See the demo of reproduction of the issue and resolution, HERE
Cheers!!

Query for a Specific Time

How can i return data from 2 days ago at 11:00:00 PM to all of yesterday ending at 11:59:59 PM?
I currently have only yesterdays date query:
SELECT *
FROM table
WHERE code = '00'
AND to_char(RQST_TMSTMP, 'yyyy-mm-dd') = to_char(sysdate-1, 'yyyy-mm-dd')
How about
select *
from table
where code = '00'
and rqst_tmstmp >= trunc(sysdate - 2) + 11/24
and rqst_tmstmp <= trunc(sysdate);
Here's what all those TRUNCs represent (so that you could follow what's going on):
SQL> select sysdate, -- today, right now
2 trunc(sysdate) ts, -- today at midnight
3 trunc(sysdate - 2) ts_2, -- 2 days ago at midnight
4 trunc(sysdate - 2) + 11/24 ts_2_11 -- 2 days ago at midnight + 11 hours
5 from dual;
SYSDATE TS TS_2 TS_2_11
---------------- ---------------- ---------------- ----------------
29.11.2018 17:07 29.11.2018 00:00 27.11.2018 00:00 27.11.2018 11:00
SQL>
If the column is capturing hours & minutes then use,
TO_CHAR(RQST_TMSTMP,'DD-MM-YY HH24:MI')

How to convert week number to date range in Oracle?

In Oracle we get week number from following query:
select to_char(TO_DATE(SYSDATE,'DD-MM-YY'),'IW') from dual
I want to get date range of given week number, for example for week no:1 date range is 01-01-2017 to 08-01-2017.
is there any way to get the date range for given week number?
"week no:1 date range is 01-01-2017 to 08-01-2017"
No it isn't. You're confusing 'IW' (which runs MON - SUN) with 'WW' which runs from the first day of the year:
SQL> with dts as (
2 select date '2017-01-01' + (level-1) as dt
3 from dual
4 connect by level <= 8
5 )
6 select dt
7 , to_char(dt, 'DY') as dy_dt
8 , to_char(dt, 'IW') as iw_dt
9 , to_char(dt, 'WW') as ww_dt
10 from dts
11 order by 1;
DT DY_DT IW WW
--------- ------------ -- --
01-JAN-17 SUN 52 01
02-JAN-17 MON 01 01
03-JAN-17 TUE 01 01
04-JAN-17 WED 01 01
05-JAN-17 THU 01 01
06-JAN-17 FRI 01 01
07-JAN-17 SAT 01 01
08-JAN-17 SUN 01 02
8 rows selected.
SQL>
However, it's easy enough to generate a range for the the IW week number. You need to multiple the IW number by 7 which you can convert to a date with the day of year mask. Then you can use next_day() function to get the previous Monday and the next Sunday relative to that date:
SQL> with tgt as (
2 select to_date( &iw *7, 'DDD') as dt from dual
3 )
4 select next_day(dt-8, 'mon') as start_date
5 , next_day(dt, 'sun') as end_date
6* from tgt;
Enter value for iw: 23
old 2: select to_date( &iw *7, 'DDD') as dt from dual
new 2: select to_date( 23 *7, 'DDD') as dt from dual
START_DAT END_DATE
--------- ---------
05-JUN-17 11-JUN-17
SQL>
Obvious this solution uses my NLS Settings (English): you may need to tweak the solution if you use different settings.
These kinds of problems are easy to solve with calendar tables.
The following query builds on the assumption (ISO 8601) that the 4th of January is present in the first week in a year. Therefore I can generate a valid date in the first week of any year by constructing the 4th of January like: to_date(year || '-01-04', 'yyyy-mm-dd'). Oracle will tell me the day of week (sun=1, sat=7) for any date using to_char(date, 'D'). The 4th of JAN 2017 happens to be a wednesday (day 4). Subtracting 3 days will give me the first day (sunday) of the first week of the year.
Now it is easy to find the start day in any given week in the year by simply adding 7 days for each week (not counting the first week).
with weeks as(
select 2017 as year, 39 as week from dual union all
select 2017 as year, 40 as week from dual union all
select 2018 as year, 35 as week from dual
)
select a.*
,to_date(year || '-01-04', 'yyyy-mm-dd') - to_number(to_char(to_date(year || '-01-04', 'yyyy-mm-dd'), 'D')) + 1 + (7 * (week-1)) as start_day
,to_date(year || '-01-04', 'yyyy-mm-dd') + 7 - to_number(to_char(to_date(year || '-01-04', 'yyyy-mm-dd'), 'D')) + (7 * (week-1)) as end_day
from weeks a;
Edit: These are the "convert" expressions you need to convert from week to date range. Note that 2017 and 39 are variable...
start date = to_date(2017 || '-01-04', 'yyyy-mm-dd') - to_number(to_char(to_date(2017 || '-01-04', 'yyyy-mm-dd'), 'D')) + 1 + (7 * (39-1))
end date = to_date(2017 || '-01-04', 'yyyy-mm-dd') + 7 - to_number(to_char(to_date(2017 || '-01-04', 'yyyy-mm-dd'), 'D')) + (7 * (39-1))
Here's a query to list all ISO weeks from 2001 to 2099
SELECT TO_CHAR(TRUNC(dt, 'IW') + 6, 'IYYY-IW') AS week,
TRUNC(dt, 'IW') AS start_date,
TRUNC(dt, 'IW') + 6 AS end_date
FROM (SELECT DATE '2001-01-01' + ((LEVEL - 1) * 7) dt
FROM DUAL
CONNECT BY LEVEL <= 5165);
For the first and last week of year this query needs some CASE logic, but for other weeks works good. This solution use current NLS settings.
select to_char( start_of_week, 'day dd.mm.yyyy' ) start_of_week,
to_char( start_of_week + 6, 'day dd.mm.yyyy' ) end_of_week
from
(
select trunc( date '2017-01-01' + 38*7 , 'day') start_of_week
from dual
)
1) date '2017-01-01' - in what year we look for weeks
or it may be trunc (sysdate, 'YEAR') to take first day of current year
2) date '2017-01-01' + 38*7 - jump to 38th week
3) trunc ( ... , 'day' ) - gives date of first day of the week
https://docs.oracle.com/cd/B19306_01/server.102/b14200/functions201.htm
https://docs.oracle.com/cd/B19306_01/server.102/b14200/functions230.htm
I use this function:
FUNCTION ISOWeekDate(WEEK INTEGER, YEAR INTEGER) RETURN DATE DETERMINISTIC IS
res DATE;
BEGIN
IF WEEK > 53 OR WEEK < 1 THEN
RAISE VALUE_ERROR;
END IF;
res := NEXT_DAY(TO_DATE( YEAR || '0104', 'YYYYMMDD' ) - 7, 'MONDAY') + ( WEEK - 1 ) * 7;
IF TO_CHAR(res, 'fmIYYY') = YEAR THEN
RETURN res;
ELSE
RAISE VALUE_ERROR;
END IF;
END ISOWeekDate;
Please note, according to my comment it is ambiguous if you only provide a week number without a year. The function returns the first day of given ISO Week.

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.

Resources