En postgres, timestamp with time zone
se puede abreviar como timestamptz
, y timestamp without time zone
como timestamp
. Usaré los nombres de tipo más cortos por simplicidad.
Obtener la marca de tiempo de Unix de un postgres timestamptz
como now()
es simple, como usted dice, solo:
select extract(epoch from now());
Eso es realmente todo lo que necesita saber para obtener el tiempo absoluto de cualquier tipo timestamptz
, incluso now()
.
Las cosas solo se complican cuando tienes un timestamp
campo.
Cuando coloca timestamptz
datos como now()
en ese campo, primero se convertirá a una zona horaria particular (ya sea explícitamente at time zone
o mediante la conversión a la zona horaria de la sesión) y la información de la zona horaria se descartará . Ya no se refiere a un tiempo absoluto. Es por eso que generalmente no desea almacenar las marcas de tiempo como las timestamp
usaría normalmente timestamptz
; tal vez una película se estrene a las 6 p.m. en una fecha particular en cada zona horaria , ese es el tipo de caso de uso.
Si solo trabaja en una zona horaria única, podría salirse con la suya timestamp
. La conversión de regreso a timestamptz
es lo suficientemente inteligente como para hacer frente a DST, y se supone que las marcas de tiempo, para fines de conversión, se encuentran en la zona horaria actual. Aquí hay un ejemplo para GMT / BST:
select '2011-03-27 00:59:00.0+00'::timestamptz::timestamp::timestamptz
, '2011-03-27 01:00:00.0+00'::timestamptz::timestamp::timestamptz;
/*
|timestamptz |timestamptz |
|:---------------------|:---------------------|
|2011-03-27 00:59:00+00|2011-03-27 02:00:00+01|
*/
DBFiddle
Pero, tenga en cuenta el siguiente comportamiento confuso:
set timezone to 0;
values(1, '1970-01-01 00:00:00+00'::timestamp::timestamptz)
, (2, '1970-01-01 00:00:00+02'::timestamp::timestamptz);
/*
|column1|column2 |
|------:|:---------------------|
| 1|1970-01-01 00:00:00+00|
| 2|1970-01-01 00:00:00+00|
*/
DBFiddle
Esto es porque :
PostgreSQL nunca examina el contenido de una cadena literal antes de determinar su tipo y, por lo tanto, tratará a ambos [...] como marca de tiempo sin zona horaria. Para asegurarse de que un literal se trate como marca de tiempo con zona horaria, dele el tipo explícito correcto ... En un literal que se ha determinado que es una marca de tiempo sin zona horaria, PostgreSQL ignorará en silencio cualquier indicación de zona horaria
SELECT FLOOR(EXTRACT(epoch FROM NOW())*1000);
no devuelve la marca de tiempo correcta porque la conversión de la zona horaria de postgres arroja la información de la zona horaria del resultado:
luego, extract mira la marca de tiempo sin zona horaria y considera que es una hora local (aunque de hecho ya es utc).
La forma correcta sería:
En la última línea, el primero
at time zone
realiza la conversión, el segundo asigna una nueva zona horaria al resultado.fuente