Je suis tellement ridiculement frustré de devoir utiliser des valeurs DateTime pour des ensembles de données qui ne sont «qu'une journée». Les anniversaires sont l'exemple le plus courant, mais cela revient tout le temps dans les applications d'entreprise.
Je me suis habitué à simplement régler la partie Heure des enregistrements "date uniquement" sur "midi" (ce qui évite que la date ne change jamais, quel que soit le fuseau horaire). Cela semble être un piratage, et je trouve toujours des bugs de développeurs juniors qui se déplacent sur ce problème.
Le temps est toujours relatif à un point fixe. 16 heures est 4 heures après le méridien, ou midi. Le point de transit le plus élevé du soleil est observable et nous permet de mettre en place un système de coordonnées. 3 heures avant midi (Ante Meridian), 2 heures après midi, 1441899402938 millisecondes depuis le 1er janvier 1970. Pour les personnes élevées dans un monde cartésien, c'est une seconde nature.
Mais notre calendrier est antérieur à Descartes. Mon argument est qu'il est plus correctement considéré comme une énumération sur laquelle une fonction modulo est appliquée. Le lundi suit le dimanche, et ainsi de suite jusqu'à ce que vous arriviez au fait que le dimanche suit le samedi. Il n'y a ni positif ni négatif, c'est un module, ou une valeur absolue.
De même avec des années se répétant. Tous les 365 jours (environ), il y a plusieurs jours spéciaux pour moi: les anniversaires, les anniversaires, les anniversaires des enfants, etc. nous POUVONS mapper cela sur un nombre à virgule flottante, et en vérité, le mapper sur ledit nombre résout BEAUCOUP de problèmes qui sont vraiment difficiles à l'ancienne, mais cela ne signifie pas que c'est la seule façon de le faire.
La connaissance et la compréhension de la nature de la «cheville carrée dans un trou rond» de l'utilisation de DateTimes pour stocker des dates font de moi un meilleur programmeur.
Y a-t-il une valeur dans une application explicitement conçue comme une application de planification dans la définition d'une classe Date, ou est-ce que "régler toutes les heures sur midi" est la meilleure approche? Quels problèmes peut-il y avoir avec l'utilisation de DateTime et la définition du composant Time sur Noon? Le décalage de fuseau horaire peut-il être pris en compte dans une telle approche? J'ai utilisé MomentJS, mais je pense que c'est juste une meilleure classe Date.
la source
Réponses:
Tout d'abord, éliminons une chose: les anniversaires sont une chose, les dates de naissance en sont une autre. Un anniversaire est un type de données exotique car il lui manque non seulement les composants des heures, des minutes, etc. mais il lui manque également le composant de l'année. Si vous voulez vraiment gérer les anniversaires, je vous recommande d'inventer votre propre type de données qui ne contient qu'un numéro de mois et un numéro de jour, et qui n'est lié à aucun des types de données date-heure intégrés.
D'un autre côté, si vous voulez aussi garder une trace de l'année de naissance, alors ce que vous avez n'est pas des anniversaires, ce sont des dates de naissance . Donc, la question devient maintenant pourquoi n'y a-t-il pas de type de données uniquement pour la date, afin que vous puissiez facilement représenter les dates de naissance, et que les langues populaires semblent plutôt vous obliger à utiliser un type qui inclut également un composant de temps.
Permettez-moi de mentionner brièvement qu'il n'est pas vrai que tous les langages de programmation n'offrent que des types de données temporelles qui incluent une composante temporelle. J'ai rencontré des types de données à date uniquement dans les SGBDR et dans leurs dialectes SQL correspondants. Mais ce n'est pas pertinent: le fait que ces types de données existent ne signifie pas qu'ils sont une bonne chose à avoir, et les SGBDR ont une longue histoire de confusion entre stockage et représentation.
Vous comprendrez pourquoi c'est une mauvaise idée d'avoir de tels types de données date seulement au moment où vous réalisez que le temps est une coordonnée. La plupart des gens ont une idée très vague de ce qu'est le temps, et cette idée contient des notions culturelles mystérieuses telles que les années, les mois et les jours, sans se rendre compte que ces notions sont exclusivement figuratives : elles ne sont utiles que pour représenter le temps à un humain et pour recevoir le temps comme entrée d'un humain. À n'importe quelle couche en dessous du contrôle GUI d'entrée de temps réel, le temps doit être, et est généralement, représenté comme une coordonnée de temps, qui est un nombre unique d'unités de temps depuis une certaine origine.
Par exemple, dans le
DateTime
type de données de Microsoft Dotnet, l'unité de temps est de 100 nanosecondes et l'origine de l'heure est 12:00 minuit, le 1er janvier 0001 CEUn autre exemple de notation arcane, exclusivement figurative, est la mesure d'angle en degrés, minutes d'un degré et secondes de degré. Bien sûr, pour effectuer tout calcul utile, vous devez utiliser en interne les radians et, si nécessaire, convertir en degrés et en degrés lorsque vous interagissez avec un utilisateur humain.
Donc, ne confondez pas la représentation lisible par l'homme d'une mesure avec la nature réelle de la mesure. Très souvent, la méthode idéale pour réaliser une mesure, qui correspond le mieux à la nature de la mesure, est très différente de la représentation lisible par l'homme de cette mesure.
À la lumière de tout cela, votre demande pour un type de données temporelles qui ne représente que des dates s'apparente à une demande pour un type de données angulaire qui ne serait capable de représenter que des degrés, empêchant explicitement une plus grande précision. Un tel type de données serait assez limité, et finalement inutile, car vous devriez quand même le convertir vers et depuis des radians afin de faire quoi que ce soit d'utile.
Votre problème avec la date de naissance est que vous avez une coordonnée de temps imprécise : la personne est, bien sûr, née à un moment précis, mais l'heure et la minute n'ont pas été enregistrées par l'hôpital, ou nous ne le faisons pas se soucient d'eux. Donc, ce qui se passe vraiment, c'est que votre coordonnée de date et d'heure de naissance a une marge d'erreur, une tolérance ou une incertitude si vous le souhaitez, et il est préférable de la traiter comme telle: mettez-la exactement au milieu de la journée, et considérons une incertitude implicite de +12-12 heures. Et c'est précisément la solution à laquelle vous êtes intuitivement arrivé.
la source
Les dates et les heures sont différentes en fonction du contexte et vous avez besoin de plusieurs types distincts pour couvrir tous les cas d'utilisation.
Le
DateTime
type présent dans de nombreuses langues représente un moment précis dans le temps ("instantané"). Au-delà de cela, nous avons un certain nombre de concepts de temps et d'intervalle de temps relatifs ou "humains" comme les jours civils, les dates récurrentes, les mois, les années, etc. qui sont dans de nombreux cas ambigus et dépendent du contexte. Ces types ne sont pas aussi universellement utiles, mais nécessaires dans des domaines d'application spécifiques comme les calendriers, les outils de planification et d'autres applications qui interagissent avec les concepts humains du temps.Si vous écrivez quelque chose comme une application de calendrier, vous bénéficierez certainement d'utiliser une bibliothèque comme Joda-time qui fournit un ensemble plus riche de types de temps. Par exemple
LocalDate
, une date sans heure. Cela a une sémantique différente de l'ordinaireDateTime
avec la partie de temps définie sur zéro, car leDateTime
indique toujours un moment précis (minuit dans un fuseau horaire spécifique), tandisLocalDate
qu'indique toute la journée et n'est pas lié à un fuseau horaire spécifique. Cela signifie également que vous ne pouvez pas traduire directement l'un en l'autre.LocalDate
est certainement plus simple queDateTime
parce qu'il n'a pas à prendre en compte les fuseaux horaires, mais vous devez être conscient des autres problèmes, par exemple que la date actuelle peut en fait reculer lorsque vous traversez un fuseau horaire, et que le même instant dans le temps peut correspondent à différentes dates dans différents fuseaux horaires. Si vous utilisez des dates locales dans des applications Web ou en réseau, vous devez faire très attention à ces problèmes. La suppression de la partie horaire d'une date ne résout pas le problème fondamental des fuseaux horaires! Et si vous prenez en considération les dates historiques et les différentes cultures, cela devient encore plus difficile, car la même date peut correspondre à des moments extrêmement différents dans le temps, par exemple le calendrier julien contre le calendrier grégorien.Vous demandez maintenant pourquoi les langues n'ont pas quelque chose comme
LocalDate
intégré . Eh bien tout d'abord, certains langages comme SQL et Visual Basic ont un type de date sans partie d'heure. Et Java a également ajouté unLocalDate
dans la version récente. Mais d'autres plateformes comme .Net ne le font pas. Seuls les concepteurs de langage peuvent vraiment expliquer pourquoi cela n'est pas inclus dans la bibliothèque standard, mais je suppose que le "temps instantané" est conceptuellement simple et universellement utile, tandis que les autres concepts de temps ne sont utiles que pour des domaines d'application spécifiques (comme les calendriers, etc. .). Il est donc logique de laisser le développeur de l'application écrire des types personnalisés pour gérer les cas d'utilisation plus complexes, ou de le laisser être géré par une bibliothèque tierce (comme Joda-time).la source
Cela est probablement dû au fait que les calendriers sont compliqués et utilisés de tant de façons différentes que personne n'a pu comprendre une classe qui soit simple mais suffisamment générale pour être utile dans de nombreux domaines.
Le type de date communément trouvé dans les langages de programmation peut être utilisé pour dater avec précision les transactions dans un système informatique. D'autres cas d'utilisation nécessiteront probablement une bibliothèque personnalisée.
Voici une courte liste de faits sur les calendriers, démontrant leur complexité - la plupart d'entre eux sont historiques, donc si vous limitez votre attention aux dates après le 1.1.1970, cela ne vous affectera pas. Cependant, si votre application doit fonctionner avec des dates antérieures à la fin du 19e siècle, ces faits importent. Les cas d'utilisation possibles sont des bases de données historiques de toutes sortes (livres, généalogie) mais aussi des actifs de grandes entreprises ou organisations encore en activité aujourd'hui.
Tous ces faits sont extraits de l'excellente FAQ de la bibliothèque de calendriers pour OCaml écrite par Julien Signolles.
Le calendrier julien a été introduit par Jules César en 45 avant JC. Il était d'usage courant jusqu'aux années 1500, lorsque les pays ont commencé à passer au calendrier grégorien (section 2.2). Cependant, certains pays (par exemple, la Grèce et la Russie) l'ont utilisé dans les années 1900, et l'église orthodoxe de Russie l'utilise toujours, comme le font d'autres églises orthodoxes.
Le passage du calendrier julien au calendrier grégorien ne s'est pas produit de manière uniforme, et selon l'année de changement, 10 à 13 jours ont été abandonnés. Par exemple, en France, le 9 décembre 1582 a été suivi du 20 décembre 1582 et en Grèce, le 9 mars 1924 a été suivi du 23 mars 1924.
Même à l'ère moderne, de nombreux calendriers différents sont utilisés (grégorien, orthodoxe, islamique et chinois) pour en citer quelques-uns, qui utilisent tous différentes manières de calculer les années et les anniversaires ou la date des célébrations religieuses.
Vous espérez maintenant un type de date regroupé avec des opérations utiles pour les opérations commerciales générales. Je suppose que les opérations commerciales générales n'existent pas. Par exemple, dans le monde de la finance, nous devons calculer:
Les fractions annuelles (comme «6 mois» correspond à «0,5»), qui sont utilisées conjointement avec un taux d'intérêt pour calculer les intérêts réels sur un prêt pour une durée donnée. Il y a 6 à 10 recettes pour calculer ces fractions, chacune différant par la façon dont elles gèrent la durée d'une année bissextile, la position de la période par rapport au dernier jour de février et la durée d'un mois.
Lors du calcul de la date, lors du calcul des anniversaires, nous utilisons un calendrier et une règle (choisis parmi un ensemble de plus de 6 règles différentes) pour déplacer un anniversaire d'un jour férié à un jour ouvrable.
Pour les personnes travaillant dans le secteur financier, tout type de calendrier ne mettant pas en œuvre toutes ces fonctions et règles est inutile. Il est probable que de nombreuses autres industries ont d'autres types d'habitudes et de conventions nécessitant des calculs personnalisés sur le calendrier.
Si vous devez garder une trace d'un seul jour civil, le meilleur moyen est probablement d'utiliser un grand entier représentant le jour julien de ce jour civil. Les algorithmes de conversion aller-retour du jour julien au jour calendaire - décrits avec l'année, le mois et le calendrier - sont largement connus et testés de manière approfondie, afin que vous puissiez les implémenter facilement dans votre application - et déterminer quelle règle est pertinente dans votre cas pour calculer l'anniversaire d'un événement survenu le 29 février.
la source
Je pense que Mike Nakis dans sa réponse ci-dessus fait un meilleur travail que moi pour expliquer comment le temps en général est une coordonnée mesurée absolue et toute autre communication, état supposé ou persistance de cette coordonnée temporelle n'est qu'une représentation abstraite de ladite coordonnée temporelle.
Vous parlez de telles représentations lorsque vous vous référez au Jour de la Semaine comme étant simplement une sorte de module de représentation d'un moment réel. En réalité, c'est un peu plus compliqué que cela. Si vous avez été chargé d'écrire une fonction qui renverra le jour de la semaine pour un moment donné, considérez les informations suivantes dont vous aurez besoin comme entrée d'un tel algorithme. Vous aurez besoin du point dans le temps, du calendrier, du fuseau horaire à prendre en compte (gardez à l'esprit, les fuseaux horaires changent TOUT LE TEMPS donc vous devez savoir quand ce fuseau horaire effectif a commencé à se terminer en coordonnées horaires spécifiques. La Corée du Nord a récemment changé la leur par exemple!), et si l'heure d'été est en vigueur, cela change aussi avec le temps. Considérez maintenant si vous avez reçu un DateTime dans le fuseau horaire local,
Vous pouvez voir à quel point cette question apparemment simple peut être compliquée.
Je connais la douleur que vous ressentez lorsque j'étais à votre place à un moment donné, corrigeant tous les bogues dans une application de planification des visites pour un produit écrit par des développeurs inexpérimentés. Le tout a dû être abandonné.
Le temps est en effet une coordonnée, mais en plus d'une simple date, considérez d'autres données sensibles au temps qui pourraient être nécessaires comme:
Durée: un intervalle de millisecondes qui peut se produire et qui signifie une durée ou un passage de temps sans coordonnées temporelles spécifiques spécifiées. Un cas d'utilisation pourrait être,
Intervalle: une plage de temps entre deux coordonnées temporelles spécifiques. Un cas d'utilisation où vous pouvez envisager un intervalle.
Un autre point rapide que je voulais faire est que vous avez fait un commentaire sur les nombres à virgule flottante pour les données temporelles et je vous le déconseille. L'arithmétique en virgule flottante entraîne inévitablement des erreurs d'arrondi qui peuvent ne pas vous donner une mesure aussi précise que nécessaire pour le temps.
Donc, en conclusion, toutes ces informations conduisent inévitablement aux considérations de conception suivantes:
la source
En bref, parce que la plupart des types d'heure sur ordinateur se concentrent sur la gestion correcte du problème d'heure et de fuseau horaire.
Il y a 2 cas marginaux qui ne sont pas bien servis par l'approche habituelle. Définir un point dans le temps qui est de l'autre côté d'un changement d'heure d'été en utilisant l'heure locale, qui est ensuite converti en UTC par une couche d'abstraction inférieure, puis vous fait 1 heure plus tôt / plus tard pour votre réunion.
L'autre consiste (selon la question) à modéliser des informations de date arbitraires, telles que l'enregistrement de la date de naissance d'une personne. Imaginez le cas où deux personnes naissent en même temps, l'une en Nouvelle-Zélande, l'autre à Hawaï. La probabilité est qu'ils auront des dates de naissance différentes sur leur passeport, et si la personne née à Hawaï déménage en Nouvelle-Zélande, elle sera considérée comme un jour plus âgée que la personne née en Nouvelle-Zélande, bien qu'elle ait vécu exactement à la même époque.
La suggestion dans la question comme fixer la date pour avoir une heure de midi, UTC fonctionnera, PRESQUE partout. Les décalages UTC vont de -12 à +14, il y a donc quelques endroits dans le Pacifique où cette approche échouera. J'ai tendance à traiter ces types de données comme des chaînes, au format aaaammjj, et si je dois faire des calculs de comparaison entre deux dates, cela peut être fait en toute sécurité comme comparaison de chaînes. Lorsque vous effectuez des comparaisons delta (par exemple entre la date et maintenant, ou combien de temps jusqu'à ce qu'elles atteignent l'âge X), vous devez vous assurer que toutes les dates sont créées dans le même décalage UTC, et pouvez ensuite utiliser les fonctions d'heure standard pour effectuer le travail.
la source
Date
type de données, vient d' être transporté dans aString
Pour les mêmes raisons, je pense, que les valeurs DateTime sont généralement spécifiées en UTC: simplicité et fiabilité . Le point d'une valeur DateTime est de spécifier un seul point dans le temps qui n'est pas affecté par le fuseau horaire, l'heure d'été, le calendrier et d'autres ajustements locaux. Les valeurs DateTime spécifient un instant (jusqu'à la limite de la résolution du type), pas une période ou un ensemble d'heures. Ces limitations permettent de comparer les valeurs DateTime de manière fiable, prévisible et simple.
Essayer de spécifier une date avec une valeur DateTime revient à essayer d'utiliser un point pour spécifier une zone.Vous pouvez faire fonctionner cela en utilisant une convention, comme "ce point représente le centre d'un cercle avec un rayon de 100m", mais il y a beaucoup de problèmes là-bas: tout le monde doit utiliser la même convention, vous devez écrire un tas de prendre en charge le code pour rendre le travail avec le mauvais type moins pénible, et il est à peu près garanti qu'à un moment donné, vous devrez spécifier une zone plus grande ou plus petite que la zone conventionnelle. Il en va de même pour les dates: vous pouvez utiliser `` midi '' comme heure conventionnelle pour spécifier les dates, mais vous entrez ensuite dans les fuseaux horaires parce que les gens s'attendent à spécifier les dates dans leur heure locale plutôt qu'en UTC. Et même si vous trouvez un moyen satisfaisant d'utiliser un DateTime pour spécifier une date, vous aurez besoin de plus d'informations pour savoir s'il s'agit d'une date absolue ou relative: est-ce le 4 juillet, 1776 ou tous les 4 juillet? Et si vous voulez répéter en utilisant une autre période? Et les calendriers ont toutes sortes de problèmes fous: certains mois sont plus longs que d'autres, certaines années sont plus longues que d'autres, certains jours sont encore plus longs que d'autres, et certains calendriers ont des lacunes. Vous ne voudriez pas résoudre ces problèmes uniquement pendant des jours entiers, car les mêmes problèmes surviennent pour des périodes plus courtes: vous aimeriez probablement être en mesure d'écrire du code qui exprime "prendre 1 pilule toutes les 4 heures" aussi facilement que "le le groupe se réunit tous les troisièmes vendredis. "
Donc, il y a beaucoup de complications à travailler avec les dates. Il est relativement (sans jeu de mots) facile de fournir un type qui spécifie un point dans le temps et de travailler avec lui comme vous le feriez pour un nombre, mais extrêmement difficile de fournir un type qui traite de toutes les façons dont les dates sont utilisées.
Comme d'autres l'ont souligné, il existe des langues et des bibliothèques qui fournissent un bon support pour les dates, et c'est souvent une bonne idée de les utiliser étant donné qu'il est assez difficile d'obtenir exactement le code lié à la date.
la source
Il existe de nombreux types de ce type dans diverses bibliothèques pour différentes langues. Il y en a presque certainement pour votre langue actuelle. Le package util Java avait une horrible API pour les calculs de temps, mais l'introduction du package java.time a rendu la vie bien meilleure. Voir java.time.LocalDate, contenant une valeur année-mois-jour, ou java.time.MonthDay, contenant uniquement un mois et un jour.
la source
La manipulation calendaire est l'un des aspects les moins bien compris de l'informatique. Des livres entiers ont été écrits sur le sujet. @MichealBlackburn a tout à fait raison de demander un type de données à date uniquement, qui ne se résout pas à un point sur une chronologie, sous réserve de réinterprétation. Historiquement, il y a eu des conflits légitimes sur la signification d'une date. Il ne faut pas chercher plus loin que l'adoption du calendrier grégorien pour découvrir à quel point il peut devenir complexe. De plus, les années n'ont pas toujours commencé le 1er janvier, même en Europe occidentale et dans ses colonies ( par exemple , la Grande-Bretagne et l'Amérique britannique ont commencé l'année le 25 mars).
la source
En réponse à:
La raison la plus courante pourrait être "parce que ce n'est pas nécessaire". Si vous voulez une date qui ne se soucie pas des heures, des minutes, des secondes, etc., alors il vous suffit de l'initialiser comme ceci:
Si vous le souhaitez, vous pouvez étendre DateTime vous-même:
Remarque: j'ignore intentionnellement l'heure et le fuseau horaire par défaut. Peu importe ce que vous les définissez, tant qu'ils sont les mêmes pour tous les
Date
art. Vous pouvez plaider en faveur de l'UTC. Vous pouvez faire un cas pour utiliser le fuseau horaire dans lequel se trouve votre serveur - de toute façon, je ne pense pas que ce soit important pour représenter une valeur imprécise commeDate
. Idem avec l'heure par défaut - vous pouvez le mettre à 0, vous pouvez le faire à midi. Ça n'a pas d'importance. Si Facebook m'envoie une notification d'anniversaire à 00h01 mais que je suis né à 23h59, je m'en fiche vraiment, et je ne serai pas offensé qu'ils aient plus de 12 heures de congé.Ce qui précède est en Java mais fonctionnerait de manière similaire dans n'importe quel langage avec un
DateTime
héritage. Java a en fait de nombreuses façons de résoudre ce problème, et ce qui précède est déconseillé (ils veulent que vous l'utilisiezCalendar
maintenant). Mais comme d' autres affichés dans les commentaires, certaines langues en fait ne fournissent uneDate
classe, sans doute précisément pour cette raison.Selon toute vraisemblance, chaque
Date
implémentation est probablement juste un wrapper pour le langageDateTime
et elle met à zéro le temps. Sinon, vous auriez besoin d'un code dupliqué pour résoudre des problèmes tels que le nombre de jours entre deux dates / dates, ou si deuxDate
s sont égaux (qu'en est-il du 29 février et du 1er mars?). Ce genre de choses est généralement résolu enDateTime
classe. Il est logique de réutiliser le même code pour aDate
.la source
LocalDate
ouDate
classe de type et vous devez « roll-your-own ».new Date(2000, 1, 1);
etnew Date(2000, 1, 1);
? Pouvez-vous dire lequel a des heures, des minutes et des secondes vides en dessous? Si vous vous inquiétez de voir apparaître des fonctions supplémentaires (comme setMinutes ()), alors vous pourriez suivre la voie de l'Date
enveloppementDateTime
au lieu d'en hériter, puis vous exposez uniquement setYear, setMonth, setDay, etc. Et ce n'est certainement pas moins correct que le DateTime de la bibliothèque que vous utilisez.