PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

PostgreSQL date() com fuso horário


Basicamente o que você quer é:
$ select starts_at AT TIME ZONE 'UTC' AT TIME ZONE 'US/Pacific' from schedules where id = 40

Eu consegui a solução deste artigo que está abaixo, que é OURO direto!!! Ele explica essa questão não trivial muito claramente, dê uma lida se você deseja entender melhor o gerenciamento do pstgrsql TZ.

Expressando carimbos de data/hora do PostgreSQL sem zonas na hora local

Aqui está o que está acontecendo. Primeiro, você deve saber que 'o fuso horário PST está 8 horas atrás do fuso horário UTC, por exemplo, 1º de janeiro de 2014, 16:30 PST (quarta, 01 de janeiro de 2014 16:00:30 -0800) é equivalente a 2 de janeiro de 2014, 00:30 AM UTC (Qui, 02 de janeiro de 2014 00:00:30 +0000). Qualquer horário após as 16h no PST passa para o dia seguinte, interpretado como UTC.

Além disso, como Erwin Brandstetter mencionou acima, o postresql tem dois tipos de dados de timestamps, um com fuso horário e outro sem. Se seus timestamps incluem um fuso horário, então um simples:
$ select starts_at AT TIME ZONE 'US/Pacific' from schedules where id = 40

vai funcionar. No entanto, se o seu carimbo de data/hora não tiver fuso horário, a execução do comando acima não funcionará e você deve PRIMEIRO converter seu carimbo de data/hora sem fuso horário para um carimbo de data/hora com um fuso horário, ou seja, um fuso horário UTC, e SÓ DEPOIS convertê-lo para o 'PST' ou 'US/ desejado. Pacific' (que são os mesmos até alguns problemas de horário de verão. Acho que você deve estar bem com qualquer um).

Deixe-me demonstrar com um exemplo onde eu crio um timestamp sem fuso horário. Vamos supor por conveniência que nosso fuso horário local é realmente 'PST' (se não fosse, fica um pouco mais complicado, o que é desnecessário para o propósito desta explicação).

Diga que eu tenho:
$ select timestamp '2014-01-2 00:30:00' AS a, timestamp '2014-01-2 00:30:00' AT TIME ZONE 'UTC' AS b,  timestamp '2014-01-2 00:30:00' AT TIME ZONE 'UTC' AT TIME ZONE 'PST' AS c, timestamp '2014-01-2 00:30:00' AT TIME ZONE 'PST' AS d

Isso vai render:
"a"=>"2014-01-02 00:30:00"   (This is the timezoneless timestamp)
"b"=>"2014-01-02 00:30:00+00" (This is the UTC TZ timestamp, note that up to a timezone, it is equivalent to the timezoneless one)
"c"=>"2014-01-01 16:30:00" (This is the correct 'PST' TZ conversion of the UTC timezone, if you read the documentation postgresql will not print the actual TZ for this conversion)
"d"=>"2014-01-02 08:30:00+00"

O último timestamp é o motivo de toda a confusão sobre a conversão de timestamp sem fuso horário de UTC para 'PST' no postgresql. Quando escrevemos:
timestamp '2014-01-2 00:30:00' AT TIME ZONE 'PST' AS d

Estamos pegando um timestamp sem fuso horário e tentamos convertê-lo para 'PST TZ (nós indiretamente assumimos que o postgresql entenderá que queremos converter o timestamp de um UTC TZ, mas o postresql tem seus próprios planos!). Na prática, o que o postgresql faz é pegar o timestamp sem fuso horário ('2014-01-2 00:30:00) e tratá-lo como se já fosse um timestamp 'PST' TZ (ou seja:2014-01-2 00:30 :00 -0800) e converte isso para o fuso horário UTC!!! Então, na verdade, ele o empurra 8 horas para a frente em vez de para trás! Assim temos (2014-01-02 08:30:00+00).

De qualquer forma, este último comportamento (não intuitivo) é a causa de toda a confusão. Leia o artigo se quiser uma explicação mais completa, na verdade obtive resultados um pouco diferentes dos seus nesta última parte, mas a ideia geral é a mesma.