sql >> Base de Datos >  >> RDS >> PostgreSQL

Representando un tiempo futuro en PostgreSQL

Parece que desea almacenar una hora local con respecto a una determinada zona horaria. En ese caso, almacene una timestamp (sin zona horaria) y la timezone en una columna separada.

Por ejemplo, suponga que desea registrar un evento que ocurrirá a las 10 a. m. del 26 de febrero de 2030 en Chicago y debe ser a las 10 a. m. hora local independientemente de la regla de zona horaria vigente en esa fecha.

Si la base de datos almacena la marca de tiempo sin zona horaria:

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 |
+---------------------+-----------------+

Luego, más tarde, puede encontrar la fecha y hora UTC del 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 |
+---------------------+

La consulta devuelve la fecha y hora UTC, 2030-02-26 16:00:00 , que corresponde a 2030-02-26 10:00:00 hora local en Chicago.

Usando AT TIME ZONE retrasa la aplicación de las reglas de zona horaria a cuando se realiza la consulta en lugar de cuando timestamptz fue insertado.

Usando AT TIME ZONE en una timestamp localiza la fecha y hora en la zona horaria dada, pero informa la fecha y hora en la zona horaria del usuario .Usando AT TIME ZONE en un timestamptz convierte la fecha y hora a la zona horaria dada, luego elimina el desplazamiento, devolviendo así una timestamp .Arriba, AT TIME ZONE se usa dos veces:primero para localizar una timestamp y al lado para convertir el timestamptz devuelto a una nueva zona horaria (UTC). El resultado es una timestamp en UTC.

Aquí hay un ejemplo que demuestra AT TIME ZONE comportamiento de en 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 y 2030-02-26 08:00:00-08 son las mismas fechas pero notificados en diferentes zonas horarias de usuario. Esto muestra que las 10 a. m. en Chicago son las 8 a. m. en Los Ángeles (usando las definiciones de zonas horarias actuales):

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

Una alternativa al uso de AT TIME ZONE dos veces es para establecer la zona horaria del usuario a UTC . Entonces podrías usar

select localtime AT TIME ZONE tzone

Tenga en cuenta que cuando se hace de esta manera, un timestamptz se devuelve en lugar de una timestamp .

Tenga en cuenta que almacenar las horas locales puede ser problemático porque puede haber horas inexistentes y horas ambiguas. Por ejemplo, 2018-03-11 02:30:00 es una hora local inexistente en America/Chicago . Postgresql normaliza las horas locales inexistentes asumiendo que se refiere a la hora correspondiente después de que haya comenzado el horario de verano (DST) (como si alguien hubiera olvidado adelantar su reloj):

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)

Un ejemplo de una hora local ambigua es 2018-11-04 01:00:00 en America/Chicago . Ocurre dos veces debido al horario de verano. Postgresql resuelve esta ambigüedad eligiendo la hora posterior, después de que finalice el horario de verano:

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 |
+---------------------+

Tenga en cuenta que esto significa que no hay forma de referirse a 2018-11-04 06:00:00 UTC almacenando las horas locales en America/Chicago zona horaria:

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 |
+---------------------+