How to convert string datetime to timestamp with time zone? - sql

How can I convert this string "09/23/2022 12:44 PM EDT" to timestamp with time zone using "to_timestamp_tz" function in oracle 19c?

EDT and EST are ambiguous as they are only valid half the year. To be consistent, you need to use US/EASTERN instead:
SELECT TO_TIMESTAMP_TZ(
REGEXP_REPLACE(
value,
'(EDT|EST)$',
'US/EASTERN'
),
'MM/DD/YYYY HH12:MI AM TZR'
) AS tz
FROM table_name;
Which, for the sample data:
CREATE TABLE table_name (value) AS
SELECT '09/23/2022 12:44 PM EDT' FROM DUAL UNION ALL
SELECT '06/23/2022 12:44 PM EDT' FROM DUAL UNION ALL
SELECT '12/23/2022 12:44 PM EDT' FROM DUAL;
Outputs:
TZ
2022-09-23 12:44:00.000000000 -04:00
2022-06-23 12:44:00.000000000 -04:00
2022-12-23 12:44:00.000000000 -05:00
fiddle

Related

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'

Add 8AM UTC to a date in oracle

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

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

Oracle - Max value from each date with date/time

I have table with column Date with timestamp, value in seconds and have query like
Table
2017-01-10 06:45:00 PM 1119
2017-01-10 03:30:00 PM 1054
2017-01-11 11:15:00 PM 379
2017-01-10 06:30:00 PM 377
2017-01-11 09:15:00 PM 375
Query
SELECT
TO_char(DtTm,'YYYY-MM-DD hh:mi:ss AM') As DataDt,
max(MaxSec) as Wait_sec, DtTimeTable.HrID,
FROM DtTimeTable
WHERE DtTimeTable.HrName in ('Dept1', 'Dept2', 'Dept3')
AND DtTm BETWEEN to_date('2017-01-08 00:00:00', 'YYYY-MM-DD hh24:mi:ss')
AND to_date('2017-01-10 23:59:59', 'YYYY-MM-DD hh24:mi:ss')
Group by TO_char(DtTm,'YYYY-MM-DD hh:mi:ss AM'),DtTimeTable.HrID
order by Wait_sec desc
This gives me All records and if i add
select * from
Query1 --(above)
where rownum <1 order by Wait_sec desc, Datadt desc;
I am only getting highest value of result set
How can get DatewithTime, Maxvalue for each date like
2017-01-10 06:45:00 PM 1119
2017-01-11 11:15:00 PM 379
Try something like this:
Select *
From (
Select t.*,
Row_number() over(partition by trunc(datecol) order by value desc nulls last) rn
From yourtable t
) where rn = 1;
It assign row number within date based on descending order your value column and then filters to get the first row
The solution below uses grouping, the MAX() aggregate function, and the FIRST/LAST function (with KEEP DENSE_RANK). If for a date the same highest value is reached more than once, it picks the first time during the day that the value was reached.
with
test_data( dt, val ) as (
select to_date('2017-01-10 06:45:00 PM', 'yyyy-mm-dd hh:mi:ss AM'), 1119 from dual
union all
select to_date('2017-01-10 03:30:00 PM', 'yyyy-mm-dd hh:mi:ss AM'), 1054 from dual
union all
select to_date('2017-01-11 11:15:00 PM', 'yyyy-mm-dd hh:mi:ss AM'), 379 from dual
union all
select to_date('2017-01-10 06:30:00 PM', 'yyyy-mm-dd hh:mi:ss AM'), 377 from dual
union all
select to_date('2017-01-11 09:15:00 PM', 'yyyy-mm-dd hh:mi:ss AM'), 375 from dual
)
-- end of test data; SQL query begins below this line (use actual table and column names)
select min(dt) keep(dense_rank last order by val) as dt, max(val) as val
from test_data
group by trunc(dt)
order by dt -- if needed
;
DT VAL
---------------------- ----------
2017-01-10 06:45:00 PM 1119
2017-01-11 11:15:00 PM 379
2 rows selected.