set timezone = 'Asia/Ho_Chi_Minh';
Defino os horários exibidos para GMT+7.
select '2021-02-16 09:00' AT TIME ZONE 'Asia/Singapore';
select '2021-02-16 09:00+06' AT TIME ZONE 'Asia/Singapore';
Saída
2021-02-16 10:00:00
2021-02-16 11:00:00
Como AT TIME ZONE
converte timestamp without time zone
para timestamp with time zone
e vice-versa ( https://www.postgresql.org/docs/current/functions-datetime.html#FUNCTIONS-DATETIME-ZONECONVERT ), e como ambas as saídas são timestamp without time zone
(você pode ver que elas não têm a parte + - ou pg_typeof
para confirmar), deduzo que ambas as literais de string são interpretadas como timestamp with time zone
.
Entendo que a segunda seleção tem a +06
parte para indicar o fuso horário, o que faz sentido.
Pergunta :
Por que a primeira seleção, que não tem parte de fuso horário + ou -, é interpretada como timestamp with time zone
a segunda seleção?
Eu sei que posso especificar o tipo com TIMESTAMP/TIMESTAMP WITH TIME ZONE ou converter com ::timestamp/::timestamptz, mas supondo que eu não faça nada disso, há alguma documentação descrevendo o que está acontecendo com o literal de string?
É por causa da preferência de tipo . Para que
at time zone
a construção funcione, o literal desconhecido que você especificou precisa sertimestamp
,timeTZ
outimestampTZ
- para quebrar o empate entre estes e escolher um, o Postgres verificapg_type.typispreferred
:TimestampTZ
é o tipo preferido nesse grupo :demo em db<>fiddle
O Postgres reescreve
at time zone
como umapg_catalog.timezone()
chamada de função. Ele é sobrecarregado e uma das variantes disponíveis aceitatimestampTZ
como o segundo parâmetro. A menos que você atribua explicitamente um tipo ao literal e escolhatimestamp
, o Postgres tem que adivinhar e escolher um para você, seguindo a preferência predefinida detimestampTZ
.Isso significa que em ambos os seus exemplos você está começando com um
timestampTZ
, que é então removido porat time zone
, retornando umtimestamp without time zone
.Como observação, este também deve ser seu tipo preferido .
Na verdade, há um problema semelhante em relação
'Asia/Singapore'
à direita. Há variantes depg_catalog.timezone()
que aceitam aninterval
em vez detext
there, mas como esses não são apenas tipos diferentes, mas também tipos de categorias diferentes, o Postgres precisa desempatar a categoria: se disponível,'S'
"Tipos de string" são preferidos, entãotext
vence. Essa tendência em relação à string é explicada no Capítulo 10. Conversão de tipo, 10.3. Funções, etapa 4.e :O literal de string em
select '2021-02-16 09:00' AT TIME ZONE 'Asia/Singapore';
(ou seja, a parte'2021-02-16 09:00'
) é interpretado como tendo um fuso horário porque você definiu o fuso horário como'Asia/Ho_Chi_Minh'
.O PostgreSQL trata
'2021-02-16 09:00'
como se estivesse2021-02-16 09:00
no formatoAsia/Ho_Chi_Minh time zone (UTC+7)
.Portanto, todos os horários são associados a estar em Ho Chi Minh. Como você mencionou, você precisará usar
SELECT '2021-02-16 09:00:00'::timestamp AT TIME ZONE 'Asia/Singapore';
e será tratado como um timestamp sem fuso horário no início. Se você nunca definiu o fuso horário para Ho Chi Minh, o PostgreSQL usará o fuso horário padrão (no meu caso, América/Nova York).