PostgreSQL convert date with timezone to a timestamp - sql

I have date stored in format DD/MM/YYYY HH24:MI TZ (datetime with timezone) in my psql database. I need to convert this date to a timestamp.
I tried to_timestamp() but it is not working with timezone.
ERROR: "TZ"/"tz"/"OF" format patterns are not supported in to_date
I tried ::timestamptz but it consider date to be in format of MM/DD/YYYY HH24:MI TZ
ERROR: date/time field value out of range
Is there any way to convert the format from DD/MM/YYYY HH24:MI TZ to MM/DD/YYYY HH24:MI TZ or convert DD/MM/YYYY HH24:MI TZ to timestamp?
e.g. "28/04/2017 13:00 +2:30"

try casting directly?..
so=# select to_timestamp('04/28/2017 13:00 +2:30','D/MM/YYYY HH24:MI TZ');
ERROR: "TZ"/"tz"/"OF" format patterns are not supported in to_date
Time: 20.850 ms
so=# select '04/28/2017 13:00 +2:30'::timestamptz;
timestamptz
------------------------
2017-04-28 10:30:00+00
(1 row)
Time: 0.554 ms
https://www.postgresql.org/docs/current/static/functions-formatting.html
to_timestamp and to_date exist to handle input formats that cannot be
converted by simple casting. For most standard date/time formats,
simply casting the source string to the required data type works, and
is much easier.
update
regarding your comment, you just need to adjust datestyle to change the parsing:
so=# set datestyle to DMY;
SET
Time: 9.997 ms
so=# select '04/28/2017 13:00 +2:30'::timestamptz;
ERROR: date/time field value out of range: "04/28/2017 13:00 +2:30"
LINE 1: select '04/28/2017 13:00 +2:30'::timestamptz;
^
HINT: Perhaps you need a different "datestyle" setting.
Time: 10.217 ms
so=# set datestyle to MDY;
SET
Time: 8.799 ms
so=# select '04/28/2017 13:00 +2:30'::timestamptz;
timestamptz
------------------------
2017-04-28 10:30:00+00
(1 row)

Related

Convert string with timezone to unix timestamp

I'm trying to convert a string with a specific timezone (not UTC) to an unix timestamp.
Conversion from strings in UTC works pretty well with unix_timestamp function:
hive> select unix_timestamp("2018-12-31 23:59:59 UTC", "yyyy-MM-dd HH:mm:ss z") as unixtime;
unixtime
1546300799
However, when I simply change the timezone (to another valid TZ name) it doesn't work:
hive> select unix_timestamp("2018-12-31 23:59:59 America/Sao_Paulo", "yyyy-MM-dd HH:mm:ss z") as unixtime;
unixtime
NULL
Any suggestions?
Your problem is the timezone itself, my understanding is that there is no direct way to do this using java cannonical id ("America/Sao_Paulo"). The correct format for the date that you are looking for (in full) should be
select unix_timestamp("2018-12-31 23:59:59 Brasilia Summer Time", "yyyy-MM-dd HH:mm:ss zzzz") as unixtime;

varchar2 string to Date format

I am trying to convert the below string value to TO_DATE but oracle is not
recognizing the date format. Where am I going wrong.
SELECT TO_DATE('Wed Oct 10 23:50:00 2018 UTC','Dy Mon DD HH24:MI:SS YYYY TZR','NLS_DATE_LANGUAGE = American')
FROM dual;
ERROR at line 1:
ORA-01821: date format not recognized
Use:
SELECT TO_TIMESTAMP_TZ('Wed Oct 10 23:50:00 2018 UTC','DY MON DD HH24:MI:SS YYYY TZR','NLS_DATE_LANGUAGE=American')
FROM dual;
TO_DATE function returns DATE datatype, which does not support timezones. You are using TZR format specifier in your query (time zone region), and this generates the error because DATE does not support this.
This documentation - Time Zones shows which datatypes supports timezones, and states that only TIMESTAMP WITH TIME ZONE and TIMESTAMP WITH LOCAL TIME ZONE do. So you must convert to one of this datatype instead of converting to DATE.
TO_TIMESTAMP_TZ function converts a literal to TIMESTAMP WITH TIME ZONE datatype.
If (and I realise it's a big 'if') the string values always contain UTC and not any other time zone values, then you could just treat that as a character literal. You would do that by changing your format model from TZR, which isn't recognised by to_date(), to "UTC" - including the double quotes:
SELECT TO_DATE('Wed Oct 10 23:50:00 2018 UTC',
'Dy Mon DD HH24:MI:SS YYYY "UTC"',
'NLS_DATE_LANGUAGE = American')
FROM dual;
TO_DATE('WEDOCT1023
-------------------
2018-10-10 23:50:00
Of course, as that is a plain date it still has no time zone information, but if you want to retain that then you need a timestamp with [local] time zone data type anyway.

Oracle (SQL Developer): How to convert TIMESTAMP string includeing UTC Offset

Objective
Identify the correct TIMESTAMP format and the cause of the issue.
Problem
Tring to load a CSV which includes timestamp including UTC offset.
2014-01-01T00:38:51.000+11:00
The format string is below.
YYYY-MM-DD"T"HH24:MI:SS.FF3TZH:TZM
However, getting an error message.
Invalid format YYYY-MM-DD"T"HH24:MI:SS.FF3TZH:TZM is specified.
SQL Developer
TIMESTAMP
TIMESTAMP with TZ
Please suggest how to fix this and the reason.
References
Oracle 9: Convert date from mm/dd/yyyy hh:mm:ss format to iso8601 formatted datetime [closed]
There is nothing wrong with the timestamp with timezone format:
SQL> select to_timestamp_tz('2014-01-01T00:38:51.000+11:00',
2 'YYYY-MM-DD"T"HH24:MI:SS.FF3TZH:TZM') as result from dual;
RESULT
---------------------------------------------------------------------------
01-JAN-14 12.38.51.000000000 AM +11:00
1 row selected.
Elapsed: 00:00:00.00
(What is DISPLAYED is in a different format - it uses my NLS_TIMESTAMP_TZ_FORMAT session parameter - but the conversion from string to timestamp with timezone worked perfectly fine.)
Definitely a SQL Developer issue - you will need to find out how this is done in their interface.

Oracle UTC Time

I'm trying to read an Oracle TIMESTAMP WITH TIMEZONE from a database in UTC-5 (NY) as UTC.
Oracle is driving me crazy:
SELECT
from_tz(MAX(TIMESTAMPWITHTIMEZONE),'UTC'),
SYS_EXTRACT_UTC(MAX(TIMESTAMPWITHTIMEZONE)),
SYS_EXTRACT_UTC(systimestamp),
SYSTIMESTAMP AT TIME ZONE 'UTC'
FROM TABLE
Results:
SYS_EXTRACT_UTC(systimestamp) gives me: 2013-02-20 14:59:04, which is probably right.
SYSTIMESTAMP AT TIME ZONE 'UTC' gives me: 2013-02-20 15:59:04 which is my own local Berlin - whatever
Now I want to have TIMESTAMPWITHTIMEZONE (TIMESTAMP(6)) as UTC
SYS_EXTRACT_UTC(MAX(TIMESTAMPWITHTIMEZONE)) is 2013-02-20 08:55:01
from_tz(MAX(TIMESTAMPWITHTIMEZONE),'UTC') is 2013-02-20 10:55:01
Srly. Oracle. I want UTC.
Which one is the right one? Or is there a better way?
The functions are different:
SYS_EXTRACT_UTC converts a TIMESTAMP WITH TIMEZONE to a TIMESTAMP (with inferred but absent timezone=UTC).
FROM_TZ converts a TIMESTAMP to a TIMESTAMP WITH TIMEZONE
These functions when applied to a single value will in general return a different result:
SQL> SELECT sys_extract_utc(localtimestamp) ext,
2 from_tz(localtimestamp, 'UTC') from_tz
3 FROM dual;
EXT FROM_TZ
--------------------- ------------------------
2013/02/20 15:34:24 2013/02/20 16:34:24 UTC
In the first case the TIMESTAMP is implicitly given the timezone of the server and then transformed into the equivalent timestamp at the UTC timezone. Note that in general you should stay away from implicit conversions.
In the second case there is no computation between timezones: the FROM_TZ function adds the geographical location to a point in time variable.
By the way there is something missing in your example: you can't apply the FROM_TZ function on a variable of type TIMESTAMP WITH TIMEZONE (tested on 9ir2 and 11ir2):
SQL> select from_tz(systimestamp, 'UTC') from dual;
select from_tz(systimestamp, 'UTC') from dual
ORA-00932: inconsistent datatypes:
expected TIMESTAMP got TIMESTAMP WITH TIME ZONE
Edit following comment:
In your case assuming that your column are of time TIMESTAMP, and knowing that they refer to the NY timezone, you could use the AT TIME ZONE expression to convert to UTC:
SQL> SELECT localtimestamp,
2 from_tz(localtimestamp, 'America/New_York') AT TIME ZONE 'UTC' utc
3 FROM dual;
LOCALTIMESTAMP UTC
--------------------- ------------------------
2013/02/20 17:09:09 2013/02/20 22:09:09 UTC
From Oracle 18c you could use TO_UTC_TIMESTAMP_TZ function:
The TO_UTC_TIMESTAMP_TZ function converts any valid ISO 8601 date represented as a string into a TIMESTAMP WITH TIMEZONE, which can optionally be used as input to the SYS_EXTRACT_UTC function.
SELECT TO_UTC_TIMESTAMP_TZ(col_name)
FROM tab_name;

Oracle DateTime query with time zones

I have a SQL Builder library that direcltly uses ADO.NET. I have a means of creating a select query with a greater-than-or-equal operator, like:
select *
from book
where book.date_created >= {some date}
My issue is that {some date} is going to always be in the UTC time zone, but it's being compared to the book.date_created column which is a TIMESTAMP(6) WITH TIME ZONE column, which will not be in the UTC timezone.
I can execute the query, but my results are off becuaes of timezone comparisons. My query is for all books where the date_created >= x, but some of the results returned are not greater than x because after subtracting 5 hours for the time zone, they are now less than x. The IDataRecord DateTime fields returned are converted to UTC using DateTime.SpecifyKind()
Can I form my query such that it interprets book.date_created in the UTC timezone?
Note: While I'd love to change my Oracle DB columns to not specify timezones, changing table structures is not something I can do.
Edit:
Currently, {some date} is a SQL Parameter. It's backing datatype is a DateTime with UTC as the timezone. As a parameter, it is a TimestampWithTZ. The Value of the parameter is a DateTime with the kind specified as UTC as well.
Update:
The issue seems to be related to my results set from the IDataRecord. When I pull DateTimes off, I use DateTime.SpecifyKind() to put them in UTC mode. The problem is, the date times come out as DateTimeKind.Unspecified. When converting from Unspecified to UTC, it just drops the timezone and declares it is UTC without changing the underlying value. I'm not sure how to have the IDataRecord pull in the TimeZone value.
You need to use the FROM_TZ function that transforms a TIMESTAMP into a TIMESTAMP WITH TIME ZONE. For example, if you know that your variable is in UTC time (+0:00):
SELECT *
FROM book
WHERE date_created >= from_tz(<timestamp>, '+0:00');
Here's a sample script that shows the behaviour you describe (your local time zone should be set to +1:00):
CREATE TABLE t (tz TIMESTAMP(6) WITH TIME ZONE);
INSERT INTO t VALUES
(to_timestamp_tz('20000101 00:00:00 +1:00','yyyymmdd hh24:mi:ss tzh:tzm'));
INSERT INTO t VALUES
(to_timestamp_tz('20000101 00:00:00 -1:00','yyyymmdd hh24:mi:ss tzh:tzm'));
-- This will return two values instead of one
SELECT *
FROM t
WHERE tz >= to_timestamp('20000101 00:00:00', 'yyyymmdd hh24:mi:ss');
-- This query will return only one row
SELECT *
FROM t
WHERE tz >= from_tz (to_timestamp('20000101 00:00:00',
'yyyymmdd hh24:mi:ss'), '+0:00');
below links will help you.
Datetime Datatypes and Time Zone Support
TIMESTAMP WITH TIME ZONE Data Type
Write Time Zone Aware Code in Oracle
ORACLE timezone summary
Oracle Date and Time data types