¿Los valores de marca de tiempo se almacenan de manera diferente en PostgreSQL cuando el tipo de datos es WITH TIME ZONEversus 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
TIMEoTIMESTAMPdifiere entre unoWITH TIME ZONEoWITHOUT 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 ZONEoWITHOUT TIME ZONE) del valor.Aquí hay ejemplos que cubren las combinaciones de esos factores:
fuente
timestamp with time zoneytimestamp 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
TIMESTAMPvariantes 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 ZONEalmacena 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 ZONEalmacena 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.Dateojava.sql.Timestamppor supuesto).Algunos dicen que ambas
TIMESTAMPvariaciones almacenan la fecha y hora UTC. Más o menos, pero es confuso decirlo así en mi opinión.TIMESTAMP WITHOUT TIME ZONEse 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 ZONEcomo aInstant. Ambos representan un punto en la línea de tiempo en UTC.Instantes preferible, en mi opinión,OffsetDateTimeya que es más autodocumentado: ATIMESTAMP WITH TIME ZONEsiempre se recupera de la base de datos como UTC, y unInstantsiempre está en UTC, por lo que es una coincidencia natural, mientras que unoOffsetDateTimepuede llevar otras compensaciones.OffsetDateTimecomo el tipo de Java mapeado. No estoy seguro de siInstancetodaví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
timestampy quétimestamptzsignifica.timestamptzsignifica un punto absoluto en el tiempo (UTC) mientras quetimestampdenota lo que mostró el reloj en una zona horaria determinada. Por lo tanto, cuando se conviertetimestamptza 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 ZONEconstructo es un desafío para la mente propio, incluso si ya comprende los tiposWITHvs.WITHOUT TIME ZONEEntonces es una elección curiosa para explicarlos. (: (AT TIME ZONEconvierte unaWITH TIME ZONEmarca de tiempo en unaWITHOUT TIME ZONEmarca 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