¿Los valores de marca de tiempo se almacenan de manera diferente en PostgreSQL cuando el tipo de datos es WITH TIME ZONE
versus WITHOUT TIME ZONE
? ¿Se pueden ilustrar las diferencias con casos de prueba simples?
postgresql
types
timestamp
timezone
Larsenal
fuente
fuente
Respuestas:
Las diferencias están cubiertas en la documentación de PostgreSQL para los tipos de fecha / hora . Sí, el tratamiento de
TIME
oTIMESTAMP
difiere entre unoWITH TIME ZONE
oWITHOUT TIME ZONE
. No afecta cómo se almacenan los valores; afecta cómo se interpretan.Los efectos de las zonas horarias en estos tipos de datos se tratan específicamente en los documentos. La diferencia surge de lo que el sistema puede saber razonablemente sobre el valor:
Con una zona horaria como parte del valor, el valor se puede representar como una hora local en el cliente.
Sin una zona horaria como parte del valor, la zona horaria predeterminada obvia es UTC, por lo que se representa para esa zona horaria.
El comportamiento difiere dependiendo de al menos tres factores:
WITH TIME ZONE
oWITHOUT TIME ZONE
) del valor.Aquí hay ejemplos que cubren las combinaciones de esos factores:
fuente
timestamp with time zone
ytimestamp without time zone
, en Postgres *, en realidad no almacenan información de zona horaria. Puede confirmar esto con un vistazo a la página de documentos de tipo de datos: ambos tipos ocupan el mismo número de octetos y tienen el rango de valores guardados, por lo que no hay espacio para almacenar información de zona horaria. El texto de la página confirma esto. Algo inapropiado: "sin tz" significa "ignorar el desplazamiento al insertar datos" y "con tz" significa "utilizar el desplazamiento para ajustar a UTC".Intento explicarlo de manera más comprensible que la documentación de PostgreSQL referida.
Ninguna de las
TIMESTAMP
variantes almacena una zona horaria (o un desplazamiento), a pesar de lo que sugieren los nombres. La diferencia está en la interpretación de los datos almacenados (y en la aplicación prevista), no en el formato de almacenamiento en sí:TIMESTAMP WITHOUT TIME ZONE
almacena la fecha y hora local (también conocida como fecha del calendario de pared y hora del reloj de pared). Su zona horaria no está especificada por lo que PostgreSQL puede decir (aunque su aplicación puede saber qué es). Por lo tanto, PostgreSQL no realiza una conversión relacionada con la zona horaria en la entrada o salida. Si el valor se ingresó en la base de datos como'2011-07-01 06:30:30'
, entonces no importa en qué zona horaria lo muestre más tarde, seguirá diciendo año 2011, mes 07, día 01, 06 horas, 30 minutos y 30 segundos (en algún formato). Además, cualquier desplazamiento o la zona horaria que especifique en la entrada es ignorada por PostgreSQL, por lo que'2011-07-01 06:30:30+00'
y'2011-07-01 06:30:30+05'
son los mismos que acaba'2011-07-01 06:30:30'
. Para desarrolladores de Java: es análogo ajava.time.LocalDateTime
.TIMESTAMP WITH TIME ZONE
almacena un punto en la línea de tiempo UTC. El aspecto (cuántas horas, minutos, etc.) depende de su zona horaria, pero siempre se refiere al mismo instante "físico" (como el momento de un evento físico real). La entrada se convierte internamente a UTC, y así es como se almacena. Para eso, se debe conocer el desplazamiento de la entrada, por lo que cuando la entrada no contiene un desplazamiento explícito o zona horaria (como'2011-07-01 06:30:30'
) se supone que está en la zona horaria actual de la sesión de PostgreSQL; de lo contrario, se utiliza la compensación o zona horaria especificada explícitamente (como en'2011-07-01 06:30:30+05'
). La salida se muestra convertida a la zona horaria actual de la sesión de PostgreSQL. Para desarrolladores de Java: es análogojava.time.Instant
(aunque con una resolución más baja), pero con JDBC y JPA 2.2 se supone que debes mapearlojava.time.OffsetDateTime
(java.util.Date
ojava.sql.Timestamp
por supuesto).Algunos dicen que ambas
TIMESTAMP
variaciones almacenan la fecha y hora UTC. Más o menos, pero es confuso decirlo así en mi opinión.TIMESTAMP WITHOUT TIME ZONE
se almacena como unTIMESTAMP WITH TIME ZONE
, que se representa con la zona horaria UTC y da el mismo año, mes, día, horas, minutos, segundos y microsegundos que en la fecha y hora local. Pero no está destinado a representar el punto en la línea de tiempo que dice la interpretación UTC, es solo la forma en que se codifican los campos de fecha y hora locales. (Es un grupo de puntos en la línea de tiempo, ya que la zona de tiempo real no es UTC; no sabemos qué es).fuente
TIMESTAMP WITH TIME ZONE
como aInstant
. Ambos representan un punto en la línea de tiempo en UTC.Instant
es preferible, en mi opinión,OffsetDateTime
ya que es más autodocumentado: ATIMESTAMP WITH TIME ZONE
siempre se recupera de la base de datos como UTC, y unInstant
siempre está en UTC, por lo que es una coincidencia natural, mientras que unoOffsetDateTime
puede llevar otras compensaciones.OffsetDateTime
como el tipo de Java mapeado. No estoy seguro de siInstance
todavía se admite de forma no oficial en alguna parte.'2011-07-01 06:30:30+00'
y'2011-07-01 06:30:30+05'
se ignora, pero soy capaz de hacerloinsert into test_table (date) values ('2018-03-24T00:00:00-05:00'::timestamptz);
y lo convertirá a utc correctamente. donde fecha es marca de tiempo sin zona horaria. Estoy tratando de entender cuál es el valor principal de la marca de tiempo con la zona horaria y tengo problemas.::timestamptz
. Con eso, convierte la cadena aTIMESTAMP WITH TIME ZONE
, y cuando eso se convierta aún másWITHOUT TIME ZONE
, almacenará el día del "calendario de pared" y la hora del reloj de pared de ese instante como se ve desde su zona horaria de sesión (que tal vez sea UTC). Todavía solo será una marca de tiempo local con desplazamiento no especificado (sin zona).Aquí hay un ejemplo que debería ayudar. Si tiene una marca de tiempo con una zona horaria, puede convertir esa marca de tiempo en cualquier otra zona horaria. Si no tiene una zona horaria base, no se convertirá correctamente.
Salida:
fuente
timestamp
y quétimestamptz
significa.timestamptz
significa un punto absoluto en el tiempo (UTC) mientras quetimestamp
denota lo que mostró el reloj en una zona horaria determinada. Por lo tanto, cuando se conviertetimestamptz
a una zona horaria, se pregunta qué mostró el reloj en Nueva York en este momento absoluto. mientras que al "convertir" atimestamp
, se pregunta cuál fue el punto absoluto en el tiempo cuando el reloj de Nueva York mostró x.AT TIME ZONE
constructo es un desafío para la mente propio, incluso si ya comprende los tiposWITH
vs.WITHOUT TIME ZONE
Entonces es una elección curiosa para explicarlos. (: (AT TIME ZONE
convierte unaWITH TIME ZONE
marca de tiempo en unaWITHOUT TIME ZONE
marca de tiempo, y viceversa ... no es exactamente obvio.)now()::timestamp AT TIME ZONE 'CST'
no tiene sentido, a menos que en qué instante un reloj para la zona 'CST' muestre la hora en que se muestra actualmente su reloj local