Meilleure pratique pour stocker DateTime basé sur TimeZone


16

Développer une application Web qui devrait permettre à l'utilisateur de planifier un rendez-vous en fonction de sa zone horaire. Et je stocke le datetime programmé par l'utilisateur en tant que datetime du serveur dans le champ de la base de données. Tout en affichant les informations de planification, la valeur a été récupérée de la base de données et convertie en fuseau horaire utilisateur. traitement dans Code base Je convertis le DateTime en fonction du fuseau horaire de l'utilisateur. Veuillez suggérer qu'il s'agit de la meilleure pratique ou qu'il existe un moyen simple?

Réponses:


33

Bienvenue dans l'un des problèmes les plus difficiles de la programmation non informatique - représentant correctement les dates et les heures pour les utilisateurs finaux.

De manière réaliste, les horodatages doivent être stockés dans une seule représentation fixe, quelle que soit la façon dont ils seront interprétés, car peu importe vos efforts, vous aurez toujours des cas ambigus et vous ne pouvez pas les résoudre sans une représentation fixe. Et vous avez choisi l'un des pires cas d'utilisation - la planification d'un rendez-vous. Le seul pire cas d'utilisation courant est le transport aérien, où un voyage peut commencer dans un fuseau horaire et se terminer dans un autre, possible à une heure locale antérieure.

Toujours, toujours, stockez TOUJOURS en UTC et affichez dans le fuseau horaire préféré ou explicitement spécifié de l'utilisateur. Dans la mesure du possible, faites en sorte que l'utilisateur vous dise dans quel fuseau horaire il croit que l'horodatage se trouve lorsqu'il l'a saisi ( par exemple , avez un champ de fuseau horaire explicite et pré-remplissez-le avec sa zone préférée).


1
+1. Et c'est flexible. Ayant un temps de référence standard commun, cohérent et universel, tout "déréférencement" de zone locale se fera correctement.
radarbob

En fait, la planification d'un rendez-vous est l'une des rares fois où vous ne pouvez pas le stocker en UTC: si les règles DST changent (ou le décalage par rapport à UTC), qu'arrive-t-il à l'heure du rendez-vous? Dans la plupart des cas, vous souhaitez que l'heure du rendez-vous reste la même localement, ce qui signifie que la valeur UTC change. Vous souhaiterez probablement stocker une valeur représentant "TimeInTimeZone + TimeZone", à partir de laquelle vous pourrez dériver facilement UTC. La programmation entre fuseaux horaires (comme les compagnies aériennes) a des contraintes qui signifient probablement qu'une combinaison des deux est utilisée.
Clockwork-Muse

1
Oh, ça devient pire que ça. J'ai régulièrement des réunions avec des collègues d'autres pays dont les règles de changement d'heure diffèrent des miennes. Lorsque cela se produit, quelle est la bonne réponse? En fait, aucun ordinateur ne peut savoir :-(
Ross Patterson

3

La manière la plus simple de traiter les informations de date / heure dépend des exigences de votre application.

Si la date et l'heure sont entrées par l'utilisateur et que le serveur n'effectue aucun traitement avec ces informations de date / heure, sauf pour les stocker dans une base de données et il n'y a aucune attente que l'heure saisie s'adapte à l'emplacement où elles sont affichées (par exemple , l'utilisateur a entré "20h00" et il doit s'afficher comme "20h00", quel que soit l'endroit du monde où il est affiché), alors le moyen le plus simple est de stocker le DateTime comme heure locale sans aucune information de fuseau horaire.

D'un autre côté, si le serveur doit utiliser la DateTime entrée comme déclencheur pour faire quelque chose, ou si l'heure doit être correctement ajustée au fuseau horaire actuel, alors votre meilleure option est de stocker la DateTime comme heure UTC et de l'ajuster à l'heure locale heure (pour l'emplacement actuel de l'utilisateur) chaque fois que vous le lisez dans la base de données.


-1 pour "stocker en heure locale", +1 pour "stocker en UTC".
Ross Patterson

@ RossPatterson: Pouvez-vous expliquer votre '-1 pour "le stocker dans l'heure locale"'? Je suis curieux de savoir pourquoi ce devrait être une mauvaise idée, compte tenu des conditions que je lui ai données.
Bart van Ingen Schenau

1
Par exemple, l'utilisation de l'heure locale de l'utilisateur signifie que chaque valeur correspond effectivement à plusieurs dizaines de types de données différents. Ce qui signifie que vous ne pouvez pas y effectuer d'opérations de base de données comme "TIMESTAMP> '2013-08-27T12: 00: 00'". Cela signifie même que vous ne pouvez pas savoir quand et si appliquer les conversions d'heure d'été.
Ross Patterson

@ RossPatterson: Merci. Je suis d'accord que l'heure locale n'est pas la bonne solution dans la plupart des cas.
Bart van Ingen Schenau

2

Il est important de ne pas confondre deux concepts liés.

Si vous manipulez un moment réel, c'est-à-dire une heure spécifique un jour spécifique, la seule façon de le faire est de toujours utiliser la valeur de l'heure UTC universelle. N'essayez jamais de stocker cela comme une valeur pertinente pour le fuseau horaire. Lorsque vous affichez cette valeur horaire à un utilisateur, convertissez toujours le fuseau horaire de l'utilisateur à ce moment. (Et n'oubliez pas que l'heure et la date dépendent du fuseau horaire.)

L'autre concept est celui d'une "expression temporelle" telle que "20h00 tous les mardis". Vous avez spécifiquement mentionné permettre aux gens de planifier des rendez-vous, et si vous avez des rendez-vous récurrents, vous avez besoin d'une expression comme ça. Je ne connais pas de langage d'expression standard, mais quoi que vous utilisiez, il sera relatif au fuseau horaire de la personne qui l'a spécifié. Il serait préférable de rendre cela explicite, par exemple "20h00 tous les mardis dans le fuseau horaire du Pacifique". Dans le cas d'une expression temporelle, vous la stockez toujours sous forme de chaîne et n'impliquez jamais de format d'heure système.

Voir plus de discussion à ce sujet sur mon blog


1

De nombreuses réponses indiquent ici le stockage au format UTC. Mais soyez très prudent avec ça. Par exemple, si vous planifiez un rendez-vous à midi mais que le rendez-vous a lieu après le passage à l'heure d'été, que se passera-t-il? UTC ne conserve aucune information indiquant si dst était actif lorsque le rendez-vous a été enregistré. Beaucoup de grands systèmes célèbres ont fait cette erreur, où un utilisateur envoie un e-mail à 9 heures du matin en été, puis en hiver, l'heure d'envoi indique 8 heures, car le calcul de retour à partir de l'UTC dépend du moment où vous regardez l'heure, pas allumé lorsque le datetime a été enregistré.

Il vaut mieux supposer que votre utilisateur souhaite toujours avoir les heures qu'il a choisies. Aucune conversion UTC, aucune conversion de temps, aucune information de fuseau horaire, rien. Prendre rendez-vous de 08h00 à 12h00 le 21 mars 2016, c'est tout. N'utilisez pas l'heure locale ou l'heure UTC, mais l'heure non spécifiée (dans json, cela n'a ni z ni +, en gros, dans .NET, cela a DateTime.Kind = DateTimeKind.Unspecified).

Bien sûr, si votre cas d'utilisation est que vous êtes une entreprise qui tient des réunions avec quelqu'un de différents fuseaux horaires et que vous souhaitez voir ces informations dans, disons, un calendrier d'entreprise, mais permettre aux utilisateurs de voir quelle heure se trouve dans leur fuseau horaire, il devient plus compliqué. L'heure doit être correcte pour différentes personnes dans différents fuseaux horaires (le fournisseur et le client).

Dans ces cas, vous pouvez même vouloir enregistrer quand le rendez-vous a été enregistré dans la base de données, dans quel fuseau horaire et si cela inclut dst ou non. De cette façon, vous pouvez toujours calculer l'heure locale à autre chose, à ce qu'elle serait maintenant ou à ce qu'elle était censée être historiquement. Parce que les fuseaux horaires ne sont pas statiques, ce qui complique encore les choses.

Heureusement, c'est là que des bibliothèques comme http://nodatime.org/ interviennent et sont fortement recommandées. Ils travaillent avec des dates beaucoup plus régulièrement. Même dans ce cas, je recommanderais d'encapsuler toutes vos variables datetime et votre logique dans vos propres wrappers, en utilisant des interfaces afin qu'elles puissent être moquées, et vous pourrez alors changer de logique plus tard.


Je ne suis pas tout à fait d'accord avec vos conclusions, mais une réunion à midi prévue à travers un changement d'heure d'été est un défi particulier, comme ce serait une réunion hebdomadaire à midi réservée plusieurs années dans le futur.
Bent

" Bien sûr, si votre cas d'utilisation est que vous êtes une entreprise qui tient des réunions avec quelqu'un de différents fuseaux horaires et que vous souhaitez voir ces informations dans, disons, un calendrier d'entreprise, mais permettre aux utilisateurs de voir quelle heure se trouve dans leur fuseau horaire, cela devient plus compliqué. "- c'est à peu près toutes les entreprises. Très peu d'entreprises en dehors de la Chine et de l'Inde peuvent ignorer les rendez-vous entre fuseaux horaires.
Ross Patterson

"De cette façon, vous pouvez toujours calculer l'heure locale à autre chose, à ce qu'elle serait maintenant ou à ce qu'elle était censée être historiquement. Parce que les fuseaux horaires ne sont pas statiques, ce qui rend les choses encore plus compliquées. " - une fois vous acceptez que vous allez faire des calculs, vous devez vraiment choisir une seule représentation pour le temps. UTC, EST (mais pas EST5EDT), IST, peu importe. Mais vous ne pouvez tout simplement pas avoir de valeurs basées sur plusieurs fuseaux horaires dans le même champ et effectuer un traitement d'agrégation légitime sur celles-ci. Traitement de l'affichage, bien sûr. Mais c'est la partie facile.
Ross Patterson

Au moins, vous pouvez toujours, correctement, convertir en UTC. Vous pouvez toujours créer un tableau de calcul ou une valeur à partir de ces informations rétrospectivement. Mais vous ne pouvez jamais aller dans l'autre sens. Notez que SQL 2016 commence à prendre en charge cela nativement, bien que malheureusement, il repose toujours sur - au moins historiquement - des données de registre pas tout à fait correctes - mais c'est encore une autre amélioration.
Arwin
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.