How to treat string as UTC timestamp? - postgresql

I have to read strings like '20190608070000' as timestamps given in UTC. Is there an easy way to do that?
This one takes UTC but needs formatted input:
postgres=# show time zone;
TimeZone
----------
CET
(1 Zeile)
postgres=# select timestamp without time zone '2019-06-08 07:00:00' at time zone 'UTC';
timezone
------------------------
2019-06-08 09:00:00+02
(1 Zeile)
Whereas to_timestamp() invariably treats all input as local time as far as I see, so the output is shifted the wrong way:
postgres=# SELECT to_timestamp('20190608070000', 'YYYYMMDDHH24MISS') AT time zone 'UTC';
timezone
---------------------
2019-06-08 05:00:00
(1 Zeile)
Actually I'm using PostgreSQL 9.6.

The return type of TO_TIMESTAMP is timestamp with time zone. The time shown is in your current session's time zone(with the UTC offset).
SET SESSION timezone TO 'CET';
SET
knayak=# SELECT to_timestamp('20190608070000', 'YYYYMMDDHH24MISS');
to_timestamp
------------------------
2019-06-08 07:00:00+02
When you transform it with AT TIME ZONE, it will show the time in UTC when it's 07:00 hours in your current time zone.
SELECT to_timestamp('20190608070000', 'YYYYMMDDHH24MISS') AT time zone 'UTC';
timezone
---------------------
2019-06-08 05:00:00
(1 row)
So, If you wish to read your timestamp in a desired format and treat that as UTC, cast the output of to_timestamp explicitly to timestamp (without time zone) and then apply AT TIME ZONE.
SELECT to_timestamp('20190608070000', 'YYYYMMDDHH24MISS') :: timestamp
AT time zone 'UTC';
timezone
------------------------
2019-06-08 09:00:00+02
(1 row)

Related

Why does PostgreSQL apparently coerce a string with timestamp to `TIMESTAMP WITH TIME ZONE` even without the time zone offset?

I am on PostgreSQL v11.10, and have the TimeZone set to UTC.
When I say select '2021-02-16 17:45+00' at time zone 'America/New_York';, I get 2021-02-16 12:45:00, which is correct and expected.
However, when I say select '2021-02-16 17:45' at time zone 'America/New_York';, I get the same result.
It seems like both strings are coerced to timestamp with time zone, which seems a bit counterintuitive to me in the case of the latter one. Why does PostgreSQL behave like that? Is it documented in the manual (I looked at the following places: AT TIME ZONE, then Date/Time Types and also Date/Time Input Interpretation and Handling of Invalid or Ambiguous Timestamps, all to no avail).
Because your TimeZone is set to UTC, any timestamp without a specified timezone will be interpreted as local to the UTC timezone. Since you as asking for a timestamp to be interpreted as America/New_York, Postgres will first interpret the timestamp as a UTC timestamp, then do the math to convert it to America/New_York.
Note that if you actually look at the types being sent to Postgres, it is not coercing into timestamp with timezone unless you specify it:
edb=# select pg_typeof('2021-02-16 17:45' at time zone 'America/New_York');
pg_typeof
-----------------------------
timestamp without time zone
(1 row)
edb=# select pg_typeof('2021-02-16 17:45+00' at time zone 'America/New_York');
pg_typeof
-----------------------------
timestamp without time zone
(1 row)
edb=# select pg_typeof('2021-02-16 17:45+00'::timestamptz at time zone 'America/New_York');
pg_typeof
-----------------------------
timestamp without time zone
(1 row)
edb=# select pg_typeof('2021-02-16 17:45+00'::timestamptz);
pg_typeof
--------------------------
timestamp with time zone
(1 row)
edb=# select pg_typeof('2021-02-16 17:45+00'::timestamp);
pg_typeof
-----------------------------
timestamp without time zone
(1 row)

How to convert column data from GMT timezone to localtime in postgres?

I have a column "last_status_change_date" which has data in GMT timestamp. I need to convert this data in "GMT-6" ..How can i achieve this ?
select last_status_change_date from bss_calling_card where card_sn ='030400091074';
last_status_change_date
-------------------------
2020-01-03 17:06:51
(1 row)
Result set should be like:
last_status_change_date
-------------------------
2020-01-03 11:06:51
(1 row)
The fallacy of timestamp with out timezone. Try:
select (cast(last_status_change_date as timestamp with time zone) at time zone 'UTC') at time zone '-06:00' last_status_change_date from ...;
This takes your timestamp and converts type to timestamp with time zone then informs Postgres which time zone it's currently in and finally indicates the time zone for your desired result.

Postgresql select output date with missing timezone offset

I've got a hard time with postgresql and timezones.
The Postgresql server is in UTC time zone.
I want to perform a query that returns the date in another timezone with the timezone offset.
I can perform a query that returns the date in a timezone but I'm missing the timezone offset
base=# SET timezone to 'utc';
SET
base=# select now();
now
------------------------------
2018-04-20 14:58:22.68038+00
(1 row)
base=# SET timezone to 'Europe/Paris';
SET
base=# select now();
now
-------------------------------
2018-04-20 16:58:29.614383+02
(1 row)
base=# SET timezone to 'utc';
SET
base=# select now() AT TIME ZONE 'Europe/Paris';
timezone
----------------------------
2018-04-20 16:59:03.146917 -- missing timezone offset here
(1 row)
Expected result
base=# SET timezone to 'utc';
SET
base=# select now() AT TIME ZONE 'Europe/Paris'; --I'm missing something here, I guess
timezone
----------------------------
2018-04-20 16:59:03.146917+02 -- That's what I want
(1 row)
Do you have any idea how to do it?
Thanks
If you use AT TIME ZONE, PG returns a timestamp without time zone. If you cast it to back to a timestamp with time zone, you get your expected result:
SELECT (NOW() AT TIME ZONE 'Europe/Paris')::TIMESTAMPTZ;
Result:
2018-04-20 18:15:26.165+02
How do you get the +02 without setting the timezone? Here's the problem: NOW() AT TIME ZONE 'Europe/Paris' returns the current time in the specified time zone (without an offset), and casting it back to TIMESTAMPTZ gives you the offset of the current time zone (of your PG session) based on UTC. Since 'Europe/Paris' is +02 from UTC, if you've set your time zone to 'Europe/Paris', the offset you get in a TIMESTAMPTZ is +02. If your current time zone setting is UTC, your offset is +00.
How to get the offset no matter what your PG session's time zone setting, without explicitly setting the time zone? I would like to think there's a better way to get the offset, but without knowing one, here's one way: calculate the offset, format it, append it to the timestamp without time zone.
SELECT (NOW() AT TIME ZONE 'Europe/Paris')::TEXT || TO_CHAR(EXTRACT(hour FROM NOW() AT TIME ZONE 'Europe/Paris' - NOW() AT TIME ZONE 'UTC'), 'FMSG00')
Result: 2018-04-21 15:12:42.658+02, and I get the same result no matter the current timezone.
Some timezone have an offset in 30 or 45 minutes.
Using TO_CHAR(EXTRACT(hour FROM NOW() AT TIME ZONE 'Europe/Paris' - NOW() AT TIME ZONE 'UTC') exclude this use case.
Did you consider to use SET LOCAL TIME ZONE 'Europe/Paris'; in a dedicated function ? According to the documentation :
If SET LOCAL is used within a function that has a SET option for the same variable (see CREATE FUNCTION), the effects of the SET LOCAL command disappear at function exit
This other reply seem's fitting your requirement : How to convert timestamp field to ISO 8601 string in a given time zone?

Convert a UTC timezone in postgresql to EST (local time)

I am new to PostgreSQL and I was wondering if there is a direct way to just convert the timestamp values in a table to a different timezone using a function. In my case it is UTC to EST.
These are the values for example that I need to convert to EST (not just one value but all the values in the table)
date
-------------------
2015-10-24 16:38:46
2016-01-19 18:27:00
2016-01-24 16:14:34
2016-02-09 23:05:49
2016-02-11 20:46:26
Here in London, we are currently 1 hour ahead of UTC. So - if I take your timezone without timestamp and say it is in UTC I will get it printed for my local timezone.
richardh=> SELECT ((timestamp '2015-10-24 16:38:46') AT TIME ZONE 'UTC');
timezone
------------------------
2015-10-24 17:38:46+01
(1 row)
But you want "EST" which seems to be somewhere in the Americas, judging by the value returned. You can wrap the expression in a little SQL function if you wanted to.
richardh=> SELECT ((timestamp '2015-10-24 16:38:46') AT TIME ZONE 'UTC') AT TIME ZONE 'EST';
timezone
---------------------
2015-10-24 11:38:46
(1 row)
Edit: how to do it in a query
SELECT ((stored_timestamp AT TIME ZONE 'UTC') AT TIME ZONE 'EST') AS local_timestamp
FROM my_table;
Similarly
execute
SELECT '2015-10-24 16:38:46'::timestamp AT time zone 'EST';
timezone
------------------------
2015-10-24 21:38:46+00
(1 row)
I usually leave everything in UTC and convert when it is time to show.
I use something like:
SELECT my_date_utc AT time zone 'utc' at time zone 'est' From ....
If you have problem accessing with your zone, you can simply pass your zone interval also.
To convert timestamp from IST to UTC.
SELECT '2020-12-14 06:38:46'::timestamp AT time zone INTERVAL '+05:30';
timezone
------------------------
2015-10-24 11:38:46+00
(1 row)
To convert timestamp from UTC to IST.
SELECT '2020-12-14 06:38:46'::timestamp AT time zone INTERVAL '-05:30';
timezone
------------------------
2020-12-14 12:08:46+00
(1 row)
It is 12:22 here in Los Angeles now.
I find that I have to reverse the UST and america/los_angeles arguments:
ods=> SELECT NOW(),(NOW() AT TIME ZONE 'america/los_angeles') AT TIME ZONE 'utc';;
now | timezone
-------------------------------+-------------------------------
2022-04-22 19:22:35.943605+00 | 2022-04-22 12:22:35.943605+00
(1 row)
Am I missing something?
You should always store the main reference of a date in UTC and either convert it to a time zone in your queries or store the specific timezone version of the data in another column. The reason for this is that it is quick and easy to convert a date from UTC to another time zone as long as you know that the timezone that it is stored as is UTC. It takes the guess work out of it. Alternatively, you can store the date WITH the timezone.
If you have an operation that automatically populates the date with the system clock of your server, then you can either
A: Change the operation to use UTC time
B: Change the system clock on the server to UTC
I had the same problem, I am working with different regions and timezones, I need to just fix the timezone in the query the way it doesn't effect other customers around the regions and I havent changed the table structure or any thing(Open–closed principle) . What I did In my query:
SELECT TO_CHAR(current_timestamp at time zone 'Australia/Melbourne', 'DD/MM/YYYY hh24:mi AM') as date_of_extract
This worked for me and I could change the 'UTC' defult timezone for my postgressql to the 'Australia/Melbourne'(any time zone you are looking into). hope this is helpful.
Building off of #Leandro Castro's answer...
To get current time in in timezone, use the CURRENT_TIME function:
SELECT CURRENT_TIME(0) AT time zone 'utc' at time zone 'est';

Retrieving UTC timestamptzs from postgres in the correct time zone

I store timestamps with time zone in my postgres database. The server time zone is UTC. All the timestamptzs are stored as UTC datetimes.
Now, I'd like to retrieve those timestamps, but for a specific time zone (e.g. US/Pacific). Because of daylight savings time, the correct time zone is sometimes PDT and sometimes PST. So I can't just run a query like select t at time zone 'pdt' because this will be wrong for the pst dates.
Is there a way to pull the dates from the database in the correct time zone?
According to the documentation, together with TIME ZONE code you can also specify locales. For your case you can use something like that:
ds=# SELECT current_setting('TIMEZONE');
current_setting
-----------------
UTC
(1 row)
ds=# SELECT now();
now
-------------------------------
2015-11-05 00:35:03.126317+00
(1 row)
pm7=# SELECT now() AT TIME ZONE 'America/Los_Angeles';
timezone
----------------------------
2015-11-04 16:35:06.344367
(1 row)