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

Representando um tempo futuro no PostgreSQL


Parece que você deseja armazenar um localtime em relação a um determinado fuso horário. Nesse caso, armazene um timestamp (sem fuso horário) e o timezone em uma coluna separada.

Por exemplo, suponha que você queira gravar um evento que ocorrerá às 10h do dia 26 de fevereiro de 2030 em Chicago e deve ser às 10h localtime independentemente da regra de fuso horário em vigor nessa data.

Se o banco de dados armazenar o timestamp sem fuso horário:
unutbu=# select '2030-02-26 10:00:00'::timestamp as localtime, 'America/Chicago' AS tzone;
+---------------------+-----------------+
|      localtime      |      tzone      |
+---------------------+-----------------+
| 2030-02-26 10:00:00 | America/Chicago |
+---------------------+-----------------+

Então, mais tarde, você pode encontrar a data e hora UTC do evento usando
unutbu=# select '2030-02-26 10:00:00'::timestamp AT TIME ZONE 'America/Chicago' AT TIME ZONE 'UTC';
+---------------------+
|      timezone       |
+---------------------+
| 2030-02-26 16:00:00 |
+---------------------+

A consulta retorna a data e hora UTC, 2030-02-26 16:00:00 , que corresponde a 2030-02-26 10:00:00 hora local em Chicago.

Usando AT TIME ZONE atrasa a aplicação das regras de fuso horário para quando a consulta é feita em vez de quando o timestamptz foi inserido.

Usando AT TIME ZONE em um timestamp localiza a data e hora para o fuso horário especificado, mas relatórios o datetime no fuso horário do usuário .Usando AT TIME ZONE em um timestamptz converte a data e hora para o fuso horário especificado e, em seguida, descarta o deslocamento, retornando um timestamp .Acima, AT TIME ZONE é usado duas vezes:primeiro para localizar um timestamp e em seguida para converter o timestamptz retornado para um novo fuso horário (UTC). O resultado é um timestamp em UTC.

Aqui está um exemplo, demonstrando AT TIME ZONE comportamento do timestamp s:
unutbu=# SET timezone = 'America/Chicago';
unutbu=# SELECT '2030-02-26 10:00:00'::timestamp AT TIME ZONE 'America/Chicago';
+------------------------+
|        timezone        |
+------------------------+
| 2030-02-26 10:00:00-06 |
+------------------------+

unutbu=# SET timezone = 'America/Los_Angeles';
unutbu=# SELECT '2030-02-26 10:00:00'::timestamp AT TIME ZONE 'America/Chicago';
+------------------------+
|        timezone        |
+------------------------+
| 2030-02-26 08:00:00-08 |
+------------------------+

2030-02-26 10:00:00-06 e 2030-02-26 08:00:00-08 são os mesmos datetimes, mas relatados em fusos horários de usuários diferentes. Isso mostra que 10h em Chicago é 8h em Los Angeles (usando as definições atuais de fuso horário):
unutbu=# SELECT '2030-02-26 10:00:00-06'::timestamptz AT TIME ZONE 'America/Los_Angeles';
+---------------------+
|      timezone       |
+---------------------+
| 2030-02-26 08:00:00 |
+---------------------+

Uma alternativa ao uso de AT TIME ZONE duas vezes é definir o fuso horário do usuário para UTC . Então você poderia usar
select localtime AT TIME ZONE tzone

Observe que, quando feito dessa maneira, um timestamptz é retornado em vez de um timestamp .

Esteja ciente de que armazenar horários locais pode ser problemático porque pode haver horários inexistentes e horários ambíguos. Por exemplo, 2018-03-11 02:30:00 é um localtime inexistente em America/Chicago . O Postgresql normaliza horários locais inexistentes assumindo que se refere ao horário correspondente após o início do horário de verão (DST) (como se alguém tivesse esquecido de adiantar o relógio):
unutbu=# select '2018-03-11 02:30:00'::timestamp AT TIME ZONE 'America/Chicago' AT TIME ZONE 'UTC';
+---------------------+
|      timezone       |
+---------------------+
| 2018-03-11 08:30:00 |
+---------------------+
(1 row)

unutbu=# select '2018-03-11 03:30:00'::timestamp AT TIME ZONE 'America/Chicago' AT TIME ZONE 'UTC';
+---------------------+
|      timezone       |
+---------------------+
| 2018-03-11 08:30:00 |
+---------------------+
(1 row)

Um exemplo de hora local ambígua é 2018-11-04 01:00:00 em America/Chicago . Ocorre duas vezes devido ao horário de verão. O Postgresql resolve essa ambiguidade escolhendo a hora posterior, após o término do horário de verão:
unutbu=# select '2018-11-04 01:00:00'::timestamp AT TIME ZONE 'America/Chicago' AT TIME ZONE 'UTC';
+---------------------+
|      timezone       |
+---------------------+
| 2018-11-04 07:00:00 |
+---------------------+

Observe que isso significa que não há como fazer referência a 2018-11-04 06:00:00 UTC armazenando horários locais no America/Chicago fuso horário:
unutbu=# select '2018-11-04 00:59:59'::timestamp AT TIME ZONE 'America/Chicago' AT TIME ZONE 'UTC';
+---------------------+
|      timezone       |
+---------------------+
| 2018-11-04 05:59:59 |
+---------------------+