web-dev-qa-db-fra.com

Meilleure pratique pour stocker DateTime sur TimeZone

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 la base de code Je convertis le DateTime en fonction du fuseau horaire de l'utilisateur. Veuillez suggérer s'il s'agit de la meilleure pratique ou s'il existe un moyen simple?

19
user46506

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 prise de 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. Si possible, demandez à l'utilisateur de vous dire dans quel fuseau horaire il pense que l'horodatage se trouve lorsqu'il le saisit ( Par exemple , avoir un champ de fuseau horaire explicite et le préremplir avec leur zone préférée).

35
Ross Patterson

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 entrée s'adapte à l'emplacement où elles sont affichées (par exemple , l'utilisateur a entré "20h00" et il devrait être affiché 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.

3

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, alors la seule façon de le faire est de toujours utiliser la valeur de l'heure UTC universelle. N'essayez jamais de le stocker en tant que valeur pertinente pour le fuseau horaire. Lorsque vous affichez cette valeur de temps à 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 aucun 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 le rendre explicite, par exemple "8:00 PM chaque mardi 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

2
AgilePro

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/ entrent en jeu 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.

2
Arwin