I get the dates in a YYYYMMDD
format.
I need to convert this column to the timestamp with specific timezone. What is the best/easiest way to do that?
So if I have 20210101
I want to get 2021-01-01 00:00:00.000000
in my TZ.
I get the dates in a YYYYMMDD
format.
I need to convert this column to the timestamp with specific timezone. What is the best/easiest way to do that?
So if I have 20210101
I want to get 2021-01-01 00:00:00.000000
in my TZ.
Strictly speaking, your request is an oxymoron:
I want to get
2021-01-01 00:00:00.000000
in my TZ.
You show a timestamp
(timestamp without time zone
) literal, which is completely orthogonal to (and ignorant of) the concept of time zones.
But you want it "in my TZ", which would imply to a timestamptz
(timestamp with time zone
) value, where the corresponding literal includes a time offset like: 2021-01-01 00:00:00.000000+01
.
Since the format YYYYMMDD
is unambiguous ISO format, you can cast to date
or timestamp
directly, safely. A cast to timestamp
assumes the time component 00:00
automatically. Produces your desired timestamp '2021-01-01 00:00'
.
SELECT '20211203'::timestamp;
If you want the result type timestamp
, we are done here.
If you want the result type timestamptz
, there is a quick-and-dirty shortcut:
SELECT '20211203'::timestamptz;
The current time zone setting is assumed for the type cast. But this introduces a dependency on a runtime settings. Notoriously unreliable, only advisable for situations where you can be certain of the current setting ...
The sure and generally advisable way is to define the target time zone with the AT TIME ZONE
construct explicitly. Say, your timezone is 'Europe/Vienna':
SELECT '20211203'::timestamp AT TIME ZONE 'Europe/Vienna';
Use a time zone name. Time zone abbreviations are treacherous for input conversion and may fail for daylight saving time (DST) or other bureaucratic nonsense. 'CET' (Central European Time) is appropriate for timestamps during "standard time". During DST periods, you'd have to use 'CEST' (Central European Summer Time).
DST is utter nonsense, but some countries, including the EU, still haven't managed to get rid of it.
db<>fiddle here - note that dbfiddle runs with time zone GB
by default.
Now you have the timestamptz
value representing the start of the day (00:00) in your given time zone. Don't be fooled by the display of timestamptz
values. That's always adjusted to the current time zone setting, but it always represents that unique point in time, just with different ways to display it.
You do understand that the time zone itself is never stored in a timestamptz
value, right? Even though timestamp with time zone
sounds like it might. See:
To force a certain display use to_char()
or some other functions to generate the desired string. There is a dedicated page Data Type Formatting Functions in the manual.
Related:
This is a conversion to timestamp with time zone
. You can format it to whatever text representation you wish. My timezone is East European Time, EET (GMT + 2), so
select to_date('20211203', 'YYYYMMDD')::timestamp at time zone 'EET';
-- 2021-12-03 00:00:00.000 +0200
The question seems to assume that timestamps can be formatted on write and that they retain time zone information. They can't and they don't, which splits the problem in two:
create table test_timestamps as
select ('20211203'||'Japan')::timestamptz as "your_timestamp";
PostgreSQL saves that in binary format in UTC
so the entire idea of formatting and time zone doesn't apply to a stored timestamp
type data. It's only formatted on read and converted to a different time zone if required.
select to_char(
"your_timestamp" AT TIME ZONE 'UTC',
'YYYY-MM-DD HH24:MI:SS.US TZHTZM')
from test_timestamps;
where at time zone
is only necessary if you want it to return the timestamp as observed elsewhere.
To keep from over complicating things:
create table dt_test (id integer, ts_fld timestamp, tsz_fld timestamp with time zone);
insert into dt_test values (1, '20211203'::date, '20211203'::date);
select * from dt_test ;
id | ts_fld | tsz_fld
----+---------------------+------------------------
1 | 2021-12-03 00:00:00 | 2021-12-03 00:00:00-08
A date
will be taken as Midnight for timestamp purposes. So either just use it as date
knowing it will be Midnight or do the explicit cast:
select '20211203'::date::timestamp, '20211203'::date::timestamptz;
timestamp | timestamptz
---------------------+------------------------
2021-12-03 00:00:00 | 2021-12-03 00:00:00-08
--Which can be shortened to:
select '20211203'::timestamp, '20211203'::timestamptz;
timestamp | timestamptz
---------------------+------------------------
2021-12-03 00:00:00 | 2021-12-03 00:00:00-08
Depending on whether you want to retain the time zone offset or not. For portability 2021-12-03 00:00:00-08
would be the better choice.