Las mejores prácticas para almacenar DateTime basado en TimeZone

16

Desarrollar una aplicación web que debería permitir al Usuario programar una cita en función de su TimeZone. Y estoy almacenando la fecha y hora programada por el usuario como fecha y hora del servidor en el campo de la base de datos. Mientras mostraba la información de programación, se recuperaba el valor de la base de datos y se convertía en la zona horaria del usuario. procesamiento en base de código Estoy convirtiendo el DateTime en función de la zona horaria del usuario. ¿Por favor sugiera que esta práctica recomendada o existe alguna manera fácil?

usuario46506
fuente

Respuestas:

33

Bienvenido a uno de los problemas más difíciles en la programación no computacional: representar adecuadamente las fechas y horas para los usuarios finales.

Siendo realistas, las marcas de tiempo deben almacenarse en una representación única fija, independientemente de cómo se interpreten, porque no importa cuánto lo intentes, siempre tendrás casos ambiguos y no podrás resolverlos sin una representación fija. Y ha elegido uno de los peores casos de uso: programar una cita. El único caso de uso común peor es el viaje aéreo, donde un viaje puede comenzar en una zona horaria y terminar en otra, posible a una hora local anterior.

Siempre, siempre, SIEMPRE almacene en UTC y visualice en la zona horaria preferida o especificada explícitamente por el usuario. Si es posible, haga que el usuario le diga en qué zona horaria cree que se encuentra la marca de tiempo cuando la ingresa ( por ejemplo , tiene un campo de zona horaria explícito y lo rellena previamente con su zona preferida).

Ross Patterson
fuente
1
+1. Y es flexible. Tener un tiempo de referencia estándar común, consistente y universal: cualquier "desreferenciación" de la zona local se realizará correctamente.
radarbob
En realidad, programar una cita es una de las pocas veces que no puede almacenarla como UTC: si las reglas del horario de verano cambian (o la compensación de UTC), ¿qué sucede con la hora de la cita? En la mayoría de los casos, desea que la hora de la cita permanezca igual localmente, lo que significa que el valor UTC cambia. Lo más probable es que desee almacenar un valor que represente "TimeInTimeZone + TimeZone", del que podría derivar UTC fácilmente. La programación de zonas horarias cruzadas (como las aerolíneas) tiene restricciones que probablemente signifiquen una combinación de ambas.
Clockwork-Muse
1
Oh, se pone peor que eso. Regularmente tengo reuniones con colegas en otras naciones cuyas reglas de cambio de horario difieren de las mías. Cuando eso sucede, ¿cuál es la respuesta correcta? En realidad, ninguna computadora puede saber :-(
Ross Patterson
3

La forma más fácil de manejar la información de fecha / hora depende de los requisitos de su aplicación.

Si el usuario ingresa la fecha y la hora y el servidor no procesa con esa información de fecha / hora, excepto para almacenarla en una base de datos y no se espera que la hora ingresada se adapte a la ubicación donde se ve (por ejemplo , el usuario ingresó "8:00 PM" y debería mostrarse como "8:00 PM" sin importar en qué parte del mundo se vea), entonces la forma más fácil es almacenar el DateTime como hora local sin ninguna información de zona horaria.

Por otro lado, si el servidor debe usar el DateTime ingresado como un disparador para hacer algo, o si la hora debe ajustarse correctamente a la zona horaria actual, entonces su mejor opción es almacenar el DateTime como hora UTC y ajustarlo a local tiempo (para la ubicación actual del usuario) cada vez que lo lea de la base de datos.

Bart van Ingen Schenau
fuente
-1 para "almacenarlo en hora local", +1 para "almacenarlo en UTC".
Ross Patterson el
@RossPatterson: ¿Puede explicar su '-1 para "almacenarlo en hora local"? Tengo curiosidad por qué debería ser una mala idea, dadas las condiciones que le di.
Bart van Ingen Schenau
1
Por ejemplo, usar la hora local del usuario significa que cada valor es efectivamente uno de varias docenas de tipos de datos diferentes. Lo que significa que no puede realizar operaciones interesantes de la base de datos en ellos como "TIMESTAMP> '2013-08-27T12: 00: 00'". Incluso significa que no puede saber cuándo y si aplicar las conversiones de horario de verano.
Ross Patterson
@RossPatterson: Gracias. Estoy de acuerdo en que la hora local no es la solución correcta en la mayoría de los casos.
Bart van Ingen Schenau
2

Es importante que no combine dos conceptos relacionados.

Si está manipulando un punto en el tiempo real, que es una hora específica en un día específico, entonces la única forma de hacerlo es usar siempre el valor de hora universal UTC. Nunca intente almacenar esto como un valor relevante para la zona horaria. Al mostrar este valor de hora a un usuario, siempre convierta a la zona horaria del usuario en ese momento. (Y no olvide que tanto la hora como la fecha dependen de la zona horaria).

El otro concepto es el de una "expresión horaria" como "8:00 PM todos los martes". Usted mencionó específicamente permitir que las personas programen citas, y si tiene citas recurrentes, necesita una expresión como esa. No conozco ningún lenguaje de expresión estándar, pero sea lo que sea que uses, será relativo a la zona horaria de la persona que lo especificó. Sería mejor hacer esto explícito, por ejemplo, "8:00 PM todos los martes en la zona horaria del Pacífico". En el caso de una expresión de tiempo, la almacena siempre como una cadena y nunca involucra ningún formato de hora del sistema.

Ver más discusión sobre esto en mi blog

AgilePro
fuente
1

Muchas respuestas aquí indican el almacenamiento como UTC. Pero ten mucho cuidado con esto. Por ejemplo, si programa una cita a las 12:00 pero la cita tiene lugar después del cambio al horario de verano, ¿qué sucederá? UTC no guarda ninguna información sobre si dst estaba activo cuando se almacenó la cita. Muchos sistemas grandes y famosos han cometido este error, donde un usuario envía un correo electrónico a las 9 a.m.en el verano, y luego en invierno la hora enviada muestra las 8 a.m., porque el cálculo de UTC depende de cuándo se mira la fecha y hora, no en cuando se registró la fecha y hora.

Mucho mejor es asumir que su usuario quiere tener los tiempos que escogió siempre. Sin conversión UTC, sin conversión de tiempo, sin información de zona horaria, nada. Hacer una cita de 08:00 a 12:00 el 21 de marzo de 2016 es solo eso. No use la hora local ni la hora UTC, sino la hora no especificada (en json esto no tiene ni z ni +, básicamente, en .NET esto tiene DateTime.Kind = DateTimeKind.Unspecified).

Por supuesto, si su caso de uso es que usted es una empresa que mantiene reuniones con alguien de diferentes zonas horarias y desea ver esta información en, por ejemplo, un calendario de la empresa, pero permite a los usuarios ver qué hora es en su zona horaria, Se vuelve más complicado. El tiempo tiene que ser correcto para diferentes personas en diferentes zonas horarias (el proveedor y el cliente).

En esos casos, incluso puede registrar cuándo se guardó la cita en la base de datos, en qué zona horaria y si eso incluía dst o no. De esa manera, siempre puede calcular la hora local en cualquier otra cosa, ya sea lo que sería ahora o lo que se pretendía que fuera históricamente. Porque las zonas horarias no son estáticas, lo que complica aún más las cosas.

Afortunadamente, aquí es donde entran bibliotecas como http://nodatime.org/ y son muy recomendables. Trabajan con fechas mucho más consistentemente. Incluso entonces, recomendaría envolver todas sus variables y lógica de fecha y hora en sus propios contenedores, utilizando interfaces para que puedan burlarse, y luego aún puede cambiar la lógica más tarde.

Arwin
fuente
No estoy del todo de acuerdo con sus conclusiones, pero una reunión al mediodía programada para un cambio de horario de verano es un desafío especial, como lo sería una reunión semanal al mediodía reservada varios años en el futuro.
Doblado
" Por supuesto, si su caso de uso es que usted es una empresa que mantiene reuniones con alguien de diferentes zonas horarias y desea ver esta información en, por ejemplo, un calendario de la empresa, pero permite a los usuarios ver qué hora es en su zona horaria, se vuelve más complicado " . Eso es prácticamente todas las empresas. Muy pocas compañías fuera de China e India pueden ignorar las citas entre zonas horarias.
Ross Patterson el
"De esa manera, siempre puedes calcular la hora local en cualquier otra cosa, ya sea a lo que sería ahora o a lo que pretendía ser históricamente. Debido a que las zonas horarias no son estáticas, lo que complica aún más las cosas " . acepta que va a hacer cálculos, realmente necesita elegir una sola representación por tiempo. UTC, EST (pero no EST5EDT), IST, lo que sea. Pero simplemente no puede tener valores basados ​​en múltiples zonas horarias en el mismo campo y hacer un procesamiento agregado legítimo en ellos. Procesamiento de pantalla, claro. Pero esa es la parte fácil.
Ross Patterson el
Al menos todavía puedes, correctamente, convertir a UTC. Siempre puede crear una tabla de cálculo o valor a partir de esta información en retrospectiva. Pero nunca puedes ir para otro lado. Tenga en cuenta que SQL 2016 comienza a admitir esto de forma nativa, aunque desafortunadamente todavía se basa en, al menos históricamente, datos de registro no del todo correctos, pero es otra mejora.
Arwin