Converting UTC time field from a POSTGRE/SQL database in SQL - sql

I am having a problem from my database.
I never been used to work in PostgreSQL, and i would like to make a select from a UTC datetime field and getting a GMT Datetime as result.
Actually my request is : select dateheure from position
What should be the Postgresql request to do what i want to do ???
Thanks a lot
Gwenael

PostgreSQL does have two datetime types:
timestamp without time zone (default implicit timestamp)
timestamp with time zone
I guess that you have table with UTC datetime (without time zone type):
CREATE TEMP TABLE datetimetest
(
datetime timestamp
);
\d datetimetest
Table "pg_temp_1.datetimetest"
Column | Type | Modifiers
----------+-----------------------------+-----------
datetime | timestamp without time zone |
INSERT INTO datetimetest SELECT CURRENT_TIMESTAMP AT TIME ZONE 'UTC';
SELECT datetime FROM datetimetest;
datetime
----------------------------
2011-08-15 15:04:06.507166
(1 row)
To get datetime in some timezone you could use AT TIME ZONE construct:
SET TIME ZONE 'UTC';
SELECT datetime AT TIME ZONE 'GMT-5' FROM datetimetest;
timezone
-------------------------------
2011-08-15 10:04:06.507166+00
(1 row)

In a different post I use a CHECK() constraint to make sure that you only store and receive UTC out of the database. Hopefully it's helpful.

Related

convert timestamp timezone to datetime with another time zone in Bigquery

I have an external table (from GCS) in bigquery that by auto scheme detect a datetime column and creates a timestamp column in the table with UTC. The time zone of my data is Central (America/Chicago).
I know that the timezone is central and I want to create another column with UTC timezone. I tried using parse_timestamp/converting to string then to datetime with timezone. But couldn't get it right. Any suggestion?
The following query will output the correct UTC time. Remember that BigQuery stores timestamps in UTC.
with sample as (
select timestamp('2021-01-10 08:00:00', 'UTC') as ts
)
select timestamp(datetime(ts), 'America/Chicago') from sample;

How to convert a column timezone from CET to CST in SQL query

Here I am trying to convert date column value from CET to CST.
I tried using NEW_TIME(SYSDATE ,'CET','CST') function, but it's giving an error saying unknown time zone. Issue here is CET is not recognised by oracle as valid timezone.
I tried using "at timezone" approach initially, but it's inserting the timezone name in the column value, which I don't want.
The three-character timezones don't adjust for daylight savings. To do that you need to use the fully specified timezone name. To illustrate, in Canada, there is central standard time, but the province of Saskatechewan does not use daylight savings, so if I want to convert right now to local time in summer where daylight savings is in play, and knowing the correct fully specified timezone names in the DB Timezone file (You can check the list installed in your DB by select * from V$TIMEZONE_NAMES;):
SELECT 'Central' locale
, extract(timezone_abbr from cast(add_months(sysdate,6) as timestamp) AT TIME ZONE 'Canada/Central') tz_abbrv
, CAST(cast(add_months(sysdate,6) as timestamp) AT TIME ZONE 'Canada/Central' as timestamp) local_time from dual
union all
SELECT 'Saskatchewan' locale
, extract(timezone_abbr from cast(add_months(sysdate,6) as timestamp) AT TIME ZONE 'Canada/Saskatchewan') tz_abbrv
, CAST(cast(add_months(sysdate,6) as timestamp) AT TIME ZONE 'Canada/Saskatchewan' as timestamp) local_time from dual;
LOCALE TZ_ABBRV LOCAL_TIME
Central CDT 03/08/2016 9:57:24.000000 AM
Saskatchewan CST 03/08/2016 8:57:24.000000 AM
Otherwise you would need to code when to switch between CST and DST in your calculations - bearing in mind that the rules for when daylight savings starts and ends has changed over time, and may change again in the future.
So respond to your comment about inserts, you need to first ensure that the column is defined to include the time zone (datatype "timestamp with timezone"), and change the CAST from "timestamp" to "timestamp with time zone" to make sure that the zone information is stored:
e.g.)
create table mbt (stz timestamp with time zone)
insert into mbt values (CAST(cast(add_months(sysdate,6) as timestamp) AT TIME ZONE 'Indian/Maldives' as timestamp with time zone) )
insert into mbt values (CAST(cast(add_months(sysdate,6) as timestamp) AT TIME ZONE 'Canada/Eastern' as timestamp with time zone) )
commit;
select * from mbt;
STZ
05/08/2016 8:06:49.000000 PM +05:00
05/08/2016 11:06:50.000000 AM -04:00
If you don't include the WITH TIME ZONE you should still get the changed value, but you won't be able to easily translate from local time to a different timezone as the values will be assumed to be in the server timezone:
drop table mbt;
create table mbt (stz timestamp);
insert into mbt values (CAST(cast(add_months(sysdate,6) as timestamp) AT TIME ZONE 'Indian/Maldives' as timestamp) );
insert into mbt values (CAST(cast(add_months(sysdate,6) as timestamp) AT TIME ZONE 'Canada/Eastern' as timestamp ) );
commit;
select * from mbt;
STZ
-------------------------------
05-AUG-16 08.13.16.000000 PM
05-AUG-16 11.13.16.000000 AM
To remove timezone you can use cast(.... as Timesamp).
Check my example.
select cast( current_timestamp at time zone 'CST' as timestamp), cast( current_timestamp at time zone 'CST' as timestamp with time zone) from dual;

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;

Querying Oracle TIMESTAMP WITH TIMEZONE

I have a column in an Oracle DB table that is of type TIMESTAMP(6) WITH TIME ZONE. There are data rows with data from different timezones, some UTC, some in other timezone offsets.
Is there a way I can query the Oracle table so that the results always come back as UTC, with the appropriate time shifting being done? Is there something that can be done on the query itself, or perhaps altering the session somehow? I've tried altering the session timezone to Utc, but this seems to only impact the CURRENT_TIMESTAMP value.
ALTER SESSION SET TIME_ZONE = 'Utc'
For example, if a value was stored as:
21-JAN-10 03.28.38.635000000 PM -05:00
the query would come back as
21-JAN-10 08.28.38.635000000 PM Utc
Example table definition
CREATE TABLE "MyDb"."Books"
(
"GUID" RAW(32) DEFAULT SYS_GUID(),
"DATE_CREATED" TIMESTAMP (6) WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
);
You should be able to use the AT TIME ZONE syntax
SELECT column_name at time zone 'UTC'
FROM your_table
i.e.
SQL> select * from foo;
COL1
---------------------------------------------------------------------------
09-FEB-12 01.48.40.072000 PM -05:00
09-FEB-12 10.49.26.613000 AM US/PACIFIC
SQL> select col1 at time zone 'UTC'
2 from foo;
COL1ATTIMEZONE'UTC'
---------------------------------------------------------------------------
09-FEB-12 06.48.40.072000 PM UTC
09-FEB-12 06.49.26.613000 PM UTC

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