简体   繁体   中英

Convert timestamp without timezone into timestamp with timezone

I have a column that is of type nullable timestamp without time zone . It is stored in my Postgres database in this format: 2021-06-24 11:00:00 . And I would like to convert it to a nullable timestamp with time zone type such that it would be displayed as 2021-06-24 11:00:00.000-00 . Notice that there is no timezone conversion.

The solution should also allow to convert from timestamp with time zone to timestamp without time zone . I did some research and was not able to find anything.

You're looking for AT TIME ZONE , which is a little confusing but can do everything you need it to.

To convert a timestamp known to be UTC to a timestamptz:

SELECT '2021-06-24 11:00:00'::timestamp AT TIME ZONE 'UTC';
=> 2021-06-24 06:00:00-05

All timestamptz values are stored internally in Postgres in UTC, and do not retain the timezone they were inserted at, so they will then show up in whatever your connection timezone is. You can cast a timestamptz back to a timestamp in your desired zone by using AT TIME ZONE again (as Erwin pointed out below, AT TIME ZONE always switches between timestamp and timestamptz):

SELECT '2021-06-24 11:00:00-00'::timestamptz AT TIME ZONE 'UTC';
=> 2021-06-24 11:00:00

SELECT '2021-06-24 11:00:00-00'::timestamptz AT TIME ZONE 'America/Chicago';
=> 2021-06-24 06:00:00

Assuming a table tbl with a timestamp column ts and timestamps that represent UTC time, the solution is:

ALTER TABLE tbl ALTER COLUMN ts type timestamptz USING ts AT TIME ZONE 'UTC';

db<>fiddle here

You may have to adapt the column default, too. See:

Misunderstanding 1 (question)

I have a column that is of type nullable timestamp without time zone. It is stored in my Postgres database in this format: 2021-06-24 11:00:00 .

timestamp or timestamptz values are never stored in any format. Formatting is in the domain of display , and largely independent from the storage type. What's stored is an 8-byte integer quantity with microsecond resolution representing a point in time. The display you show is the standard Postgres text representation using ISO 8601 (also unambiguous for input). Clients using the binary protocol might choose a different representation. Even clients using the text protocol might choose to reformat differently.

Misunderstanding 2 (question)

I would like to convert it to a nullable timestamp with time zone type such that it would be displayed as 2021-06-24 11:00:00.000-00 .

The displayed time offset is not determined by the data type. You'll only see timezone -00 appended if that's true for the current TimeZone setting (typically UTC). Else, you get a different offset, and the timestamp is shifted accordingly.

Misunderstanding 3 (answer)

To represent it in UTC (the output value here looks like it has no timezone, but the type is timestamptz):

 SELECT '2021-06-24 11:00:00'::timestamp AT TIME ZONE 'UTC' AT TIME ZONE 'UTC'; => 2021-06-24 11:00:00

No, the type of the output value is timestamp . timestamptz in default text representation never "looks" like timestamp . timestamp never "has" a time zone. Not even timestamptz "has" a time zone, it's just displayed for a given time zone. Neither of the two types stores any time zone information at all. See:

Misunderstanding 4 (answer)

To cast a timestamptz back to a timestamp at UTC time:

 SELECT ('2021-06-24 11:00:00-00'::timestamptz AT TIME ZONE 'UTC')::timestamp; => 2021-06-24 11:00:00

No. Just:

SELECT '2021-06-24 11:00:00-00'::timestamptz AT TIME ZONE 'UTC';

The result is type timestamp . No additional cast.
The AT TIME ZONE construct converts between timestamp and timestamptz . The resulting type is always switched from the input.

Basics here:

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM