Add 8AM UTC to a date in oracle - sql

I have a date something like below :
Thu Nov 29 18:00:00 CST 2018
Thu Apr 26 01:00:00 BST 2018
I need to convert it to 8AM UTC in oracle.
How do i do this ?
It is a string not date.
Referred link deals with proper dates and there is no accepted answer for it.
Thanks in Advance

Since it's a string you could use regexp_replace.
regexp_replace(nmuloc, '[[:digit:]]{2}:[[:digit:]]{2}:[[:digit:]]{2} [A-Z]{3}', '08:00:00 GMT')

Oracle Setup
CREATE TABLE table_name ( datetime TIMESTAMP WITH TIME ZONE );
INSERT INTO table_name
SELECT TIMESTAMP '2018-11-29 18:00:00 CST' FROM DUAL UNION ALL
SELECT TIMESTAMP '2018-04-26 01:00:00 Europe/London' FROM DUAL UNION ALL
SELECT TIMESTAMP '2018-06-26 00:00:00 Europe/London' FROM DUAL;
Query 1:
Use datetime AS TIME ZONE 'UTC' to convert it from your time zone to UTC
Then use TRUNC() to truncate it back to the start of the UTC day (and also cast it to a date)
Because its now a date, use CAST( ... AS TIMESTAMP ) to get it back to a timestamp
Then use FROM_TZ( ..., 'UTC' ) to get it to be a timestamp in the UTC time zone
Then add INTERVAL '8' HOUR to be 8am.
Like this:
SELECT FROM_TZ(
CAST(
TRUNC( datetime AT TIME ZONE 'UTC' )
AS TIMESTAMP
),
'UTC'
) + INTERVAL '8' HOUR AS utc_date_at_8am_utc
FROM table_name;
Output:
UTC_DATE_AT_8AM_UTC
--------------------------------
30-NOV-18 08.00.00.000000 AM UTC
26-APR-18 08.00.00.000000 AM UTC
25-JUN-18 08.00.00.000000 AM UTC
Note: this translates 2018-06-26 00:00:00 BST to 2018-06-25 23:00:00 UTC before truncating. So it will be the same UTC day (but not necessarily the same day in the local time zone).
Query 2
If this is an issue then just remove the initial time zone conversion:
SELECT FROM_TZ(
CAST(
TRUNC( datetime )
AS TIMESTAMP
),
'UTC'
) + INTERVAL '8' HOUR AS date_at_8am_utc
FROM table_name
Output:
DATE_AT_8AM_UTC
--------------------------------
29-NOV-18 08.00.00.000000 AM UTC
26-APR-18 08.00.00.000000 AM UTC
26-JUN-18 08.00.00.000000 AM UTC

Related

How to convert unix timestamp and aggregate min and max date in Oracle SQL Developer?

I have table in Oracle SQL like below:
ID | date | place
-----------------------------
123 | 1610295784376 | OBJ_1
444 | 1748596758291 | OBJ_1
567 | 8391749204754 | OBJ_2
888 | 1747264526789 | OBJ_3
ID - ID of client
date - date in Unix timestamp in UTC
place - place of contact with client
And I need to aggregate above date to achieve results as below, so I need to:
convert unix timestamp in UTC from column "date" to normal date as below
calculate min and max date for each values from column "place"
min_date
max_date
distinct_place
2022-01-05
2022-02-15
OBJ_1
2022-02-10
2022-03-20
OBJ_2
2021-10-15
2021-11-21
OBJ_3
You can use:
SELECT TIMESTAMP '1970-01-01 00:00:00 UTC'
+ MIN(date_column) * INTERVAL '0.001' SECOND(3)
AS min_date,
TIMESTAMP '1970-01-01 00:00:00 UTC'
+ MAX(date_column) * INTERVAL '0.001' SECOND(3)
AS max_date,
place
FROM table_name
GROUP BY place;
Note: the (3) after SECOND is optional and will just explicitly specify the precision of the fractional seconds.
or:
SELECT TIMESTAMP '1970-01-01 00:00:00 UTC'
+ NUMTODSINTERVAL( MIN(date_column) / 1000, 'SECOND')
AS min_date,
TIMESTAMP '1970-01-01 00:00:00 UTC'
+ NUMTODSINTERVAL( MAX(date_column) / 1000, 'SECOND')
AS max_date,
place
FROM table_name
GROUP BY place;
Which, for the sample data:
CREATE TABLE table_name (ID, date_column, place) AS
SELECT 123, 1610295784376, 'OBJ_1' FROM DUAL UNION ALL
SELECT 444, 1748596758291, 'OBJ_1' FROM DUAL UNION ALL
SELECT 567, 1391749204754, 'OBJ_2' FROM DUAL UNION ALL -- Fixed leading digit
SELECT 888, 1747264526789, 'OBJ_3' FROM DUAL;
Both output:
MIN_DATE
MAX_DATE
PLACE
2021-01-10 16:23:04.376000000 UTC
2025-05-30 09:19:18.291000000 UTC
OBJ_1
2014-02-07 05:00:04.754000000 UTC
2014-02-07 05:00:04.754000000 UTC
OBJ_2
2025-05-14 23:15:26.789000000 UTC
2025-05-14 23:15:26.789000000 UTC
OBJ_3
db<>fiddle here

Is it possible to order by truncated timestamp in SQL (oracle)?

I have a use case where I want to order by time, but at a certain resolution. For example my schema saves timestamps out to 9 decimals (nanosecond precision), but I only want to order by minutes and use a different field to order within that minute. I tried this
select * from myTable order by (cast(myTimeStamp at time zone 'UTC' as timestamp) - to_timestamp('01-JAN-01'))/1000000000*60 desc, id desc;
To convert the timestamp into epoch and then divide to get minute precision. But this gives the wrong ordering. Also when I do a dump on the above command to understand the returned data type I see data type: typ=190 and I can't find that type in the oracle docs which adds to my confusion.
So I'm wondering what I'm missing? It should be possible to order by a truncated (to minute) timestamp, any help is appreciated.
Convert the TIMESTAMP WITH TIME ZONE to the UTC time zone so that you can compare identical times and then TRUNCate it back to the start of the minute:
SELECT *
FROM myTable
ORDER BY
TRUNC(myTimeStamp at time zone 'UTC', 'MI') DESC,
id DESC;
Which, for the sample data:
CREATE TABLE myTable(
id NUMBER,
myTimestamp TIMESTAMP WITH TIME ZONE
);
INSERT INTO myTable(id, myTimestamp)
SELECT 1, TIMESTAMP '1970-01-01 00:00:00 UTC' FROM DUAL UNION ALL
SELECT 2, TIMESTAMP '1970-01-01 00:00:00 America/New_York' FROM DUAL UNION ALL
SELECT 3, TIMESTAMP '1970-01-01 00:00:00 Asia/Hong_Kong' FROM DUAL UNION ALL
SELECT 4, TIMESTAMP '1970-01-01 00:00:00 Europe/Paris' FROM DUAL UNION ALL
SELECT 5, TIMESTAMP '1970-01-01 01:00:00 UTC' FROM DUAL UNION ALL
SELECT 6, TIMESTAMP '1970-01-01 01:00:00 America/New_York' FROM DUAL UNION ALL
SELECT 7, TIMESTAMP '1970-01-01 01:00:00 Europe/Berlin' FROM DUAL;
Outputs:
ID
MYTIMESTAMP
6
01-JAN-70 01.00.00.000000 AMERICA/NEW_YORK
2
01-JAN-70 00.00.00.000000 AMERICA/NEW_YORK
5
01-JAN-70 01.00.00.000000 UTC
7
01-JAN-70 01.00.00.000000 EUROPE/BERLIN
1
01-JAN-70 00.00.00.000000 UTC
4
01-JAN-70 00.00.00.000000 EUROPE/PARIS
3
01-JAN-70 00.00.00.000000 ASIA/HONG_KONG
If you want to see the values converted to UTC that are being used in the sorting process then just add it in the output:
SELECT t.*,
TO_CHAR(TRUNC(myTimeStamp at time zone 'UTC', 'MI'), 'YYYY-MM-DD HH24:MI:SS')
AS converted_ts
FROM myTable t
ORDER BY
TRUNC(myTimeStamp at time zone 'UTC', 'MI') DESC,
id DESC;
Which outputs:
ID
MYTIMESTAMP
CONVERTED_TS
6
01-JAN-70 01.00.00.000000 AMERICA/NEW_YORK
1970-01-01 06:00:00
2
01-JAN-70 00.00.00.000000 AMERICA/NEW_YORK
1970-01-01 05:00:00
5
01-JAN-70 01.00.00.000000 UTC
1970-01-01 01:00:00
7
01-JAN-70 01.00.00.000000 EUROPE/BERLIN
1970-01-01 00:00:00
1
01-JAN-70 00.00.00.000000 UTC
1970-01-01 00:00:00
4
01-JAN-70 00.00.00.000000 EUROPE/PARIS
1969-12-31 23:00:00
3
01-JAN-70 00.00.00.000000 ASIA/HONG_KONG
1969-12-31 16:00:00
If you just use TRUNC without converting to a common time zone then it will order based on the date and time components without considering the relative difference in the time zones.
db<>fiddle here
Why don't you then just truncate timestamp to minutes?
SQL> alter session set nls_date_format = 'dd.mm.yyyy hh24:Mi:ss';
Session altered.
SQL> select systimestamp col_1,
2 trunc(systimestamp, 'mi') col_2
3 from dual;
COL_1 COL_2
---------------------------------------- -------------------
29.12.21 20:32:50,178000 +01:00 29.12.2021 20:32:00
SQL>
Then you'd
order by trunc(timestamp_column, 'mi'),
yet_another_column

ORACLE DATE FILTER NOT SHOWING CORRECT DATE RESULT

I have data as
ID MYDATE
1 2020-02-02 19:45:00:00
1 2020-02-02 20:00:00:00
I need to get data of only min_date.
So I have used query as (considering eastern and utc time zone)
SELECT ID, MYDATE
FROM MYTABLE
WHERE TO_CHAR(FROM_TZ(TO_TIMESTAMP(TO_CHAR(MYDATE.'YYYY-MM-DD HH24.MI.SS'),'YYYY-
MM-DD HH24.MI.SS), 'AMERICA/NEW_YORK) AT TIME ZONE 'UTC', 'YYYYMMDD') =
'20200202'
I get result for 2020-02-02 (which is expected)
1 2020-02-02 19:45:00:00
But when I run for date '20200203' I am getting
1 2020-02-02 20:00:00:00
which I should not be getting( I shouldn't be getting any results)
Help is appreciated!
With 2 rows of sample data it is ... challenging to give the solution that you are looking for. But here is a query that gives you the row with the lowest date for an id:
WITH tab (id, mydate)
AS
(
SELECT 1, TO_DATE('2020-02-02 19:45:00','YYYY-MM-DD HH24:MI:SS') FROM DUAL union
SELECT 1, TO_DATE('2020-02-02 20:00:00','YYYY-MM-DD HH24:MI:SS') FROM DUAL
),
ordered_dates AS
(
SELECT
id,
mydate,
ROW_NUMBER() OVER (PARTITION BY id ORDER BY mydate) AS rn FROM tab
)
SELECT id, TO_CHAR(mydate,'YYYY-MM-DD HH24:MI:SS') FROM ordered_dates WHERE rn = 1;
AMERICA/NEW_YORK timezone is UTC -4, so when you convert AMERICA/NEW_YORK to UTC, you get
original time + 4 hour,ie 2020-02-03 01:00:00 UTC:
WITH t (id, mydate)
AS
(
SELECT 1, TO_DATE('2020-02-02 19:45:00','YYYY-MM-DD HH24:MI:SS') FROM DUAL union
SELECT 2, TO_DATE('2020-02-02 20:00:00','YYYY-MM-DD HH24:MI:SS') FROM DUAL
)
select
TO_CHAR(MYDATE,'YYYY-MM-DD HH24.MI.SS') original_time,
FROM_TZ(
TO_TIMESTAMP(
TO_CHAR(MYDATE,'YYYY-MM-DD HH24.MI.SS')
,'YYYY-MM-DD HH24.MI.SS'
),
'AMERICA/NEW_YORK'
)
AT TIME ZONE 'UTC'
as UTC_TIME
from t;
ORIGINAL_TIME UTC_TIME
------------------- --------------------------------------
2020-02-02 19.45.00 2020-02-03 00:45:00.000000000 UTC
2020-02-02 20.00.00 2020-02-03 01:00:00.000000000 UTC
2 rows selected.
And you do not need to_timestamp(to_char(... in this case, it's easier to use CAST:
FROM_TZ(cast(MYDATE as timestamp),'AMERICA/NEW_YORK') AT TIME ZONE 'UTC'

Oracle - Convert Unixtime to local datetime including DST (Daylight Savings Time) and vice versa

I have a NUMBER field (UTCSTAMP) with UnixTimestamps and I would like to have a (custom) function to easily return local datetime (Europe/Amsterdam) including DST (Daylight Savings Time).
The output should be this format: 'yyyy-mm-dd hh24:mi:ss'
For example: unix_ts2date_function(1576666800)
I found this article: Convert Unixtime to Datetime SQL (Oracle) but it doesn't take Daylight Savings Time into account.
I would also like to have a (custom) function to easily convert a local datetime (Europe/Amsterdam) including DST (Daylight Savings Time) to a UnixTimestamp and use it in a WHERE clause.
For example:
SELECT * FROM table
WHERE UTCSTAMP > date2unix_ts_function('2019-05-01') (DST is active)
AND UTCSTAMP < date2unix_ts_function('2020-11-30') (DST not active)
I also found this article: Convert timestamp datatype into unix timestamp Oracle but it also doesn't take Daylight Savings Time into account.
Add a utcstamp seconds to the epoch 1970-01-01 UTC (as a TIMESTAMP data type) and then use AT TIME ZONE to convert it to your desired time zone:
Oracle Setup:
CREATE TABLE your_table ( utcstamp ) AS
SELECT 1576666800 FROM DUAL
Query:
SELECT ( TIMESTAMP '1970-01-01 00:00:00 UTC' + utcstamp * INTERVAL '1' SECOND )
AT TIME ZONE 'Europe/Amsterdam' AS Amsterdam_Time
FROM your_table
Output:
| AMSTERDAM_TIME |
| :--------------------------------------------- |
| 2019-12-18 12:00:00.000000000 EUROPE/AMSTERDAM |
Query 2:
If you want it as a DATE then just wrap everything in a CAST:
SELECT CAST(
( TIMESTAMP '1970-01-01 00:00:00 UTC' + utcstamp * INTERVAL '1' SECOND )
AT TIME ZONE 'Europe/Amsterdam'
AS DATE
) AS Amsterdam_Time
FROM your_table
Output:
| AMSTERDAM_TIME |
| :------------------ |
| 2019-12-18 12:00:00 |
db<>fiddle here
CREATE FUNCTION DATE_TO_UTCEPOCHTIME (
dt IN DATE,
tz IN VARCHAR2 DEFAULT 'UTC'
) RETURN NUMBER DETERMINISTIC
IS
BEGIN
RETURN ROUND(
( CAST( FROM_TZ( dt, tz ) AT TIME ZONE 'UTC' AS DATE )
- DATE '1970-01-01' )
* 24 * 60 * 60
);
END;
/
CREATE FUNCTION UTCEPOCHTIME_TO_DATE(
utctime IN NUMBER,
tz IN VARCHAR2 DEFAULT 'UTC'
) RETURN DATE DETERMINISTIC
IS
BEGIN
RETURN ( TIMESTAMP '1970-01-01 00:00:00 UTC' + utctime * INTERVAL '1' SECOND )
AT TIME ZONE tz;
END;
/
then you can do:
SELECT utcepochtime_to_date( utcstamp, 'Europe/Amsterdam' )
FROM your_table;
Which outputs:
| UTCEPOCHTIME_TO_DATE(UTCSTAMP,'EUROPE/AMSTERDAM') |
| :------------------------------------------------ |
| 2019-12-18 12:00:00 |
and
SELECT date_to_utcepochtime(
DATE '2019-12-18' + INTERVAL '12:00:00' HOUR TO SECOND,
'Europe/Amsterdam'
) AS utcepochtime
FROM DUAL;
which outputs:
| UTCEPOCHTIME |
| -----------: |
| 1576666800 |
db<>fiddle here
You can achieve it using the following query where we have used FROM_TZ to convert UTC to Europe/Amsterdam time:
SQL> SELECT
2 TO_CHAR(FROM_TZ( CAST( DATE '1970-01-01' + 1576666800/(24*60*60) AS TIMESTAMP ), 'UTC' )
3 AT TIME ZONE 'Europe/Amsterdam', 'yyyy-mm-dd hh24:mi:ss') as "desired_date"
4 FROM
5 DUAL;
desired_date
-------------------
2019-12-18 12:00:00
SQL>
Daylight saving is automatically handled when we use the long name of the timezone which is 'Europe/Amsterdam' in our case.
Cheers!!

Converting a timestamp with Time zone to just a timestamp

Trying to insert some data into a a table. However, I tried i am receiving data compatibility issues. The column that I am trying to insert into is a timestamp(6) column while the column I am drawing data from is a timestamp with timezone column. I know how to use cast to convert from timestamp to a timestamp with timezone but not the inverse. Is there a way I can just strip out the 'UTC'?
Date I am starting out with:
'20-MAY-18 09.00.00.000000000 AM UTC'
Date I want to end up with:
'20-MAY-18 09.00.00.000000000 AM'
What I have tried thus far:
select to_date('20-MAY-18 09.00.00.000000000 AM UTC', 'dd-mon-yy hh:mi:ss A.M.') from dual;
However I receive an error, and I just can't seem to figure it out, what am I doing wrong? thanks in advance!
You can cast a timestamp with time zone to a plain timestamp:
cast(<your_value> as timestamp)
so with your value:
select cast(
to_timestamp_tz('20-MAY-18 09.00.00.000000000 AM UTC', 'DD-MON-RR HH:MI:SS.FF AM TZR')
as timestamp)
from dual;
CAST(TO_TIMESTAMP_T
-------------------
2018-05-20 09:00:00
If you insert as timestamp with tome zone value into a plain timestamp column then it will be converted automatically, just losing its tie zone information.
If the values might not always be UTC then you can convert them to UTC and to a plain timestamp in one go with sys_extract_tc():
with cte (tsz) as (
select timestamp '2018-05-20 09:00:00.0 UTC' from dual
union all select timestamp '2018-05-20 13:00:00.0 America/New_York' from dual
)
select tsz, cast(tsz as timestamp) as ts, sys_extract_utc(tsz) utc
from cte;
TSZ TS UTC
------------------------------ ------------------- -------------------
2018-05-20 09:00:00.000 +00:00 2018-05-20 09:00:00 2018-05-20 09:00:00
2018-05-20 13:00:00.000 -04:00 2018-05-20 13:00:00 2018-05-20 17:00:00