¿Cuál es un caso de uso válido para usar TIMESTAMP SIN ZONA HORARIA?

41

Hay una respuesta larga y bastante esclarecedora sobre las diferencias entre

  • TIMESTAMP WITH TIME ZONE -vs-
  • TIMESTAMP WITHOUT TIME ZONE

disponible en esta publicación SO . Lo que me gustaría saber es: ¿hay algún caso de uso válido para usar realmente TIMESTAMP WITHOUT TIME ZONEo debería considerarse un antipatrón?

Marcus Junius Brutus
fuente
Esta pregunta corre el riesgo de cerrarse por estar "principalmente basada en la opinión". He tratado de dar algunas opiniones objetivas en mi respuesta a continuación.
Colin 't Hart
2
Este problema es bastante real, cada tipo de datos tiene un significado muy diferente. Por lo tanto, ciertamente no consideraría esta pregunta como principalmente basada en la opinión.
Basil Bourque

Respuestas:

30

Esto se afirma en muchos lugares, pero creo que vale la pena mencionar siempre cuando comparamos la timestamp with time zonecon timestamp without time zonetipos: el timestamp WITH time zoneno almacena la zona horaria información junto con la marca de tiempo . Lo que hace es almacenar todos los datos en la zona horaria UTC, como se indica en los documentos :

Para la marca de tiempo con zona horaria, el valor almacenado internamente siempre está en UTC (hora universal coordinada, tradicionalmente conocida como hora media de Greenwich, GMT). Un valor de entrada que tiene una zona horaria explícita especificada se convierte a UTC utilizando el desplazamiento apropiado para esa zona horaria. Si no se establece una zona horaria en la cadena de entrada, se supone que se encuentra en la zona horaria indicada por el parámetro TimeZone del sistema, y ​​se convierte a UTC utilizando el desplazamiento para la zona horaria.

Se considera válido para algunos usar timestamp WITHOUT time zoneen situaciones en las que (1) todo está en la misma zona horaria o (2) la capa de aplicación maneja la zona horaria y simplemente almacena todo en una determinada zona horaria (generalmente UTC). Pero también se considera un antipatrón, simple porque la solución correcta para (1) es configurar la configuración de TimeZone en la zona horaria dada para el sistema y (2) ya está resuelto, ya que PostgreSQL ya almacena todo en la misma zona horaria (UTC).

Ahora, con esos dos caídos, puedo venir con solo una buena razón para usar timestamp WITHOUT time zone. Es entonces cuando desea almacenar eventos en el futuro y que se debe activar algún tipo de alerta cuando lleguemos a ese momento. Eso podría ser bueno timestamp WITH time zonesi, y solo si, las reglas definidas por las leyes de la región sobre la zona horaria nunca cambian. La regla más común que cambia es acerca de la adopción o no del horario de verano (DST).

Por ejemplo, imagine que está en, digamos, 2013-06-15(todavía no en horario de verano) programar algún evento para que ocurra 2013-01-15 10:00(que ya estaría en horario de verano), y en 2013-06-15su región fue designado para adoptar horario de verano; pero, algún tiempo después de eso, el gobierno cambió la regla y dijo que su región ya no usará DST, y de repente su hora programada se convierte 2013-01-15 11:00(en lugar de 10:00), que si usa timestamp WITH time zoney mantiene sus configuraciones de TZ actualizadas. Por supuesto, también puede notar que es posible tratar tales casos también con la zona horaria, si realiza un seguimiento de los cambios de las reglas en las regiones / zonas horarias de su interés y actualiza los registros afectados.

Vale la pena mencionar que algunas regiones a menudo cambian estas reglas (como en Brasil, algunos estados, no todo el país, a menudo cambian), pero en la mayoría de los casos lo cambia muy temprano, por lo que sus usuarios se verían afectados solo por eventos programados muy lejos de La hora actual.

Con todo lo dicho, solo tengo una sugerencia más. Si tiene usuarios, registros o cualquier cosa en diferentes zonas horarias, almacene la zona horaria de donde provienen y elija y use timestamp with time zone. De esa manera, puede (1) cruzar eventos que ocurren más cerca unos de otros para diferentes fuentes (independientemente de sus zonas horarias) y (2) mostrar la hora original (la hora del reloj) en que ocurrió el evento.

MatheusOl
fuente
Estás diciendo: "Solo puedo venir con una buena razón para usar la marca de tiempo con la zona horaria". Si eso no es un error tipográfico, ¿está sugiriendo que la "marca de tiempo sin zona horaria" es en realidad más apropiada / menos propensa a producir malentendidos que la "marca de tiempo con zona horaria"? Eso me parece contrario a la intuición.
Marcus Junius Brutus
@MarcusJuniusBrutus, perdón por eso, de hecho fue un error tipográfico y pensé al revés ... Verifique la respuesta editada.
MatheusOl
codeblog.jonskeet.uk/2019/03/27/… discute en profundidad exactamente este escenario de futuro-evento-reglas-podría cambiar (con la misma conclusión)
Beni Cherniavsky-Paskin
19

Sí. Hay casos de uso para TIMESTAMP WITHOUT TIME ZONE.

  • En las aplicaciones comerciales comunes, este tipo solo se usaría para:
    • Reserva de citas futuras
    • Representando la misma hora del día en varias zonas horarias, como el mediodía del 23 en Tokio y en París (dos momentos diferentes, horas separadas, la misma hora del día)
  • Para el seguimiento de momentos, puntos específicos en la línea de tiempo, use siempre TIMESTAMP WITH TIME ZONE, no WITHOUT.

TIMESTAMP WITHOUT TIME ZONElos valores no son un punto en la línea de tiempo, no son momentos reales. Representan una idea aproximada sobre los posibles momentos, posibles puntos en la línea de tiempo a lo largo de un rango de aproximadamente 26-27 horas (el rango de zonas horarias de todo el mundo). No tienen un significado real hasta que aplique una zona horaria o un desplazamiento desde UTC .

Ej: navidad

Por ejemplo, supongamos que necesita registrar el inicio de días festivos / días santos.

Table: holiday_

Column: year_         Type: SMALLINT
Column: description_  Type: VARCHAR
Column: start_        Type: TIMESTAMP WITHOUT TIME ZONE

Para registrar el hecho de que la Navidad comienza después de la medianoche del 25 de diciembre de este año, tenemos que decir 2016-12-25 00:00:00sin zona horaria. Temprano en los días de Papá Noel visita Auckland, Nueva Zelanda, justo después de la medianoche, ya que es una de las primeras noches en el mundo. Luego se dirige hacia el oeste, a medida que pasa la medianoche siguiente, y pronto llega a Filipinas. Luego, los renos se mueven en dirección oeste, llegando a la India a la medianoche, que ocurre varias horas después de la medianoche de Auckland. Mucho más tarde todavía es medianoche en París FR, y aún más tarde en Montreal CA. Todas estas visitas de Santa suceden en diferentes momentos, es tiempo , pero todas ocurrieron poco después de la medianoche, según la medianoche de cada localidad.

Por lo tanto, grabar 2016-12-25 00:00:00sin zona horaria al comienzo de la Navidad es informativo y legítimo, pero solo vagamente. Hasta que diga "Navidad en Auckland" o "Navidad en Montreal", no tenemos un momento específico en el tiempo. Si está grabando el momento real cada vez que el trineo aterrizó, usaría en TIMESTAMP WITH TIME ZONElugar del WITHOUTtipo.

Similar a la Navidad es la víspera de Año Nuevo. Cuando cae el Times Square Ball en Nueva York , la gente en Seattle todavía está enfriando su champán y preparando sus cuernos de fiesta . Sin embargo, registraríamos la idea del momento de Año Nuevo como 2017-01-01 00:00:00en a TIMESTAMP WITHOUT TIME ZONE. Por el contrario, si queremos registrar cuándo cayó la pelota en Nueva York, o cuando la gente en Seattle tocó sus cuernos, en su lugar usaríamos TIMESTAMP WITH TIME ZONE(no WITHOUT) para registrar esos momentos reales, cada tres horas separados el uno del otro.

Ej: turnos de fábrica

Otro ejemplo podría ser registrar una política que implique la hora del reloj de pared en varias ubicaciones. Digamos que tenemos fábricas en Detroit, Düsseldorf y Delhi. Si decimos que en las tres fábricas el primer turno comienza a las 6 AM con un receso para el almuerzo a las 11:30 AM, eso podría registrarse como a TIMESTAMP WITHOUT TIME ZONE. Nuevamente, esta información es útil de una manera vaga, pero no indica un momento específico en el tiempo hasta que apliquemos una zona horaria. Un nuevo día amanece más temprano en el este. Entonces, la fábrica de Delhi será la primera en abrir a las 6 AM. Horas después, la fábrica de Düsseldorf comienza a funcionar a las 6 de la mañana. Pero la fábrica de Detroit en realidad no abrirá hasta otras seis horas más tarde, cuando sean las 6 AM.

Contraste esta idea (de cuándo comienza generalmente el turno de fábrica) con el hecho histórico de cuándo hizo cada trabajador de fábrica para iniciar su turno en un día en particular. El reloj de entrada es un momento real, un punto real en la línea de tiempo. Entonces registraríamos eso en una columna de tipo en TIMESTAMP WITH TIME ZONElugar del WITHOUTtipo.

Entonces, sí, hay casos de uso legítimos para TIMESTAMP WITHOUT TIME ZONE. Pero en mi experiencia con las aplicaciones comerciales, son relativamente raras. En los negocios, tendemos a preocuparnos por los momentos reales: cuándo llegó realmente la factura, cuándo entra en vigencia exactamente ese contrato, en qué momento se ejecutó esa transacción bancaria. Entonces, en situaciones tan comunes, queremos el TIMESTAMP WITH TIME ZONEtipo.

Para obtener más información, consulte mi Respuesta a la pregunta similar: ¿Debo almacenar marcas de tiempo UTC o tiempo local para turnos?

Postgres

Tenga en cuenta que Postgres específicamente nunca guarda la información de zona horaria especificada al insertar una marca de tiempo.

  • TIMESTAMP WITH TIME ZONE
    • Cualquier zona horaria especificada o desplazamiento incluido con los datos de entrada se usa para ajustar el valor a UTC y se almacena. La información de zona / desplazamiento aprobada se descarta. Piensa en TIMESTAMP WITH TIME ZONEcomo TIMESTAMP WITH RESPECT FOR TIME ZONE.
    • Una entrada de las 12:00 del mediodía del 7 de marzo de este año en la India tendrá su hora del día ajustada a UTC restando cinco horas y media: 6:30 a.m.
  • TIMESTAMP WITHOUT TIME ZONE
    • Cualquier zona horaria especificada o desplazamiento incluido con los datos de entrada se ignora por completo.
    • Una entrada de las 12:00 del mediodía del 7 de marzo de este año en la India se registra como las 12:00 del 7 de marzo de este año sin ajustes.

El estándar SQL apenas toca temas de comportamiento y tipos de datos de fecha y hora. Por lo tanto, la base de datos varía ampliamente en el manejo de fecha y hora.

Albahaca Bourque
fuente
Además, con los turnos de fábrica (u hospital), cualquier persona que trabaje en el turno del cementerio en los días del cambio de horario de verano tendrá sus horas registradas incorrectamente o sin zona horaria ...
Jasen
Creo que hay un error tipográfico en el último ejemplo: 'Una entrada de las 12:00 del mediodía del 7 de marzo ... debe ser' registrada como 12 : 00 '(no 21:00)
TmTron
11

Me gustaría agregar otra vista a esto, que va en contra de gran parte de lo que se ha escrito en las otras respuestas. En mi opinión, timestamp with time zonetiene muy pocos casos de uso válidos y timestamp without time zone, en general, debería preferirse.

Primero, debe comprender el patrón "UTC en todas partes", que generalmente se recomienda para todas las aplicaciones que no tienen requisitos muy especiales. Simplemente significa que su aplicación debe representar todas sus marcas de tiempo en UTC, en todas partes, todo el tiempo. Por supuesto, estará mostrando la fecha / hora local a los usuarios, pero la idea es convertirlos en el borde de su programa, al representar la vista. Este es el lugar correcto para combinar la marca de tiempo UTC (que puede haber cargado desde una base de datos) y la zona horaria del usuario (que puede haber venido del navegador) en una marca de tiempo local.

Si sigue este patrón, entonces timestamp with time zonees un antipatrón. Todo lo que hace este tipo es hacer que PostgreSQL realice conversiones de zona horaria al leer y escribir marcas de tiempo, según la TimeZonevariable de sesión de PostgreSQL . En lugar de tratar con zonas horarias en los bordes de su aplicación, las ha introducido en su corazón, en la comunicación con su base de datos. Debe tener cuidado de tener PostgreSQL siempre TimeZoneconfigurado correctamente en todo momento, agregando otro punto innecesario de falla y confusión.

¿Y para qué? Si sigue el patrón UTC en todas partes, su aplicación solo tiene marcas de tiempo UTC de todos modos; Entonces, ¿por qué pedirle a su base de datos que haga conversiones de zona horaria en ellos? Simplemente puede almacenarlos en una timestamp without time zonecolumna y tratarlos como si siempre fueran UTC. Sin conversiones, sin zonas horarias, sin complicaciones.

Shay Rojansky
fuente
2
Creo que los defensores de la marca de tiempo también apoyan el patrón "UTC en todas partes". ¿Es solo que la regla se aplica a nivel de la base de datos en lugar de depender solo de los desarrolladores de aplicaciones / API para hacerla cumplir? Si puede hacer cumplir esa práctica, ¿por qué no? Además, puede exigir que todas las conexiones postgres establezcan su zona horaria en UTC. Incluso si no lo hacen, el formato ISO contendrá el desplazamiento tz. Entonces, ¿no es eso lo mismo que UTC en todas partes sino forzado?
iamnat
3
Primero, si su PostgreSQL TimeZone está configurado para cualquier cosa que no sea UTC y está usando la marca de tiempo, su programa está leyendo marcas de tiempo que no son UTC. Esto simplemente no es el patrón "UTC en todas partes", y dependiendo del idioma de su cliente puede o no crear muchas complicaciones. O eres UTC en todas partes, o estás usando marcas de tiempo locales ...
Shay Rojansky
En segundo lugar, una vez más, si eres UTC en todas partes en tu aplicación, simplemente no hay desplazamiento tz para enviar en el formato ISO para tus marcas de tiempo. Los detalles variarán de un idioma a otro, pero lo ideal sería utilizar un tipo de cliente que no pueda representar nada más que una marca de tiempo UTC (por ejemplo, un Instanceen NodaTime / JodaTime). Básicamente está describiendo una situación en la que casi se sigue "UTC en todas partes", o se sigue un poco ...
Shay Rojansky
Una vez más, es muy fácil imaginar una nueva instancia de PostgreSQL configurada en algún servidor, reteniendo accidentalmente la zona horaria de la máquina local que está configurada de manera predeterminada. Las aplicaciones leen de este servidor y obtienen marcas de tiempo locales en una zona horaria totalmente arbitraria (en la que se encuentra el servidor). ¿Por qué querríamos esta complicación adicional?
Shay Rojansky
1
Podría, pero entonces tendría menos sentido usarlo timestamptz. El objetivo de este tipo es realizar conversiones de zona horaria como valores leídos y escritos en PostgreSQL (internamente en la base de datos, la marca de tiempo siempre se guarda como UTC). Establecer siempre la zona horaria de la sesión en UTC deshabilita efectivamente esas conversiones, entonces, ¿por qué usarlas timestamptz? Dicho de otra manera, si los valores en la base de datos son UTC, y los valores que entran y salen de la base de datos son siempre UTC, entonces ¿por qué tener conciencia de zona horaria en su base de datos?
Shay Rojansky
2

La datemarca de tiempo tampoco incluye información de zona horaria, sin embargo, mucha gente la usa.

Por supuesto, eso en sí mismo no es una respuesta.

Es válido para usar timestampy datepara cualquier marca de tiempo y fecha que siempre estén en la misma zona horaria, o que se almacenen en relación con alguna zona horaria conocida.

Si la zona horaria es siempre la misma o implícita, entonces es más antipatrón almacenarla que no almacenarla (información redundante).

Las marcas de tiempo también se pueden utilizar para almacenar información técnica, como la utilizada en los registros de aplicaciones o para mediciones de rendimiento. En este caso, la zona horaria también puede no ser importante.


Por el contrario, si está diseñando o trabajando en un sistema distribuido o en cualquier sistema en el que partes del sistema se distribuirán en diferentes zonas horarias, podría considerarse un antipatrón para no usar timestamp with timezone, aunque algunos sistemas podrían estar diseñados para ejecutarse en una zona horaria, por ejemplo, UTC. En este caso, la lógica de la zona horaria puede estar siendo introducida en la capa de aplicación, pero lo consideraría un antipatrón, sí.

Colin 't Hart
fuente
Entiendo que en ciertos casos no duele usarlo timestamp without timezone, pero ¿alguna vez me compra algo? De lo contrario, ¿por qué debería molestarme si el timestamp with timezone datatipo es siempre igual o más apropiado?
Marcus Junius Brutus
No almacenar información redundante sería mi argumento principal. Supongo que la aritmética de fechas también timestamp without timezonesería más rápida, pero eso probablemente solo sea importante si está procesando miles de millones de filas ...
Colin 't Hart
1
@ Colin'tHart timestampy timestamptzambos se almacenan de la misma manera. No hay información de zona horaria almacenada en a timestamptz, sino que se convierte a UTC para almacenamiento. Yo diría que siempre se usa timestamptzcuando las marcas de tiempo en cuestión denotan tiempo absoluto . Eso es todo lo que timestamptzsignifica. He escrito sobre esto aquí .
fphilipe
2

Puede parecer tentador almacenar y procesar fechas / horas en hora local si su solicitud se limita a una sola zona horaria, pero creo que esto es un error.

Al volver del horario de verano a la hora estándar, se repite una hora en la hora local (suponiendo que la diferencia sea una hora). En el lugar donde vivo, esto suele suceder alrededor de las 2 a.m., por lo que la hora local corre 01:58, 01:59, 01:00 y solo avanza a las 02:00 al final de la hora repetida.

Si intenta ordenar eventos por hora utilizando la hora local, eso significa que los eventos de dos horas separadas se mezclan y no aparecen en el orden en que realmente ocurrieron.

En comparación, UTC no tiene este problema y hace un pedido limpio. Por lo tanto, incluso cuando trabaja con una sola zona horaria, desea que el DB almacene y procese las horas en UTC y las convierta a / desde la hora local para la entrada / visualización. Este es el comportamiento de TIMESTAMP WITH TIME ZONE.

Steve Fosdick
fuente