Devoxxfr – Back to basics, ne perdez plus votre temps avec les dates

Les problèmes de date, ça arrive à tout le monde : Microsoft, Apple, Twitter. Donc ça vous est arrivé …​ ou ça va vous arriver.

Avant

Au début, on utilisait le soleil pour mesurer le temps. Ca permettait juste de savoir le milieu de la journée. Et pour des villes qui sont sur le même fuseau horaire, l’heure solaire (l’heure vraie) peut être différente. Pour éviter ça, on utilise une heure standard. La première était GMT (maintenant dépréciée en faveur d’UTC).

Le temps repose sur la seconde, une unité dans laquelle on a confiance, puisqu’elle est définie par un élément physique régulier et mesurable. Aujourd’hui, c’est défini par un nombre donné d’oscillations de l’atome de césium. C’est le temps atomique international. Ce temps sert de base au temps UTC. Il est stable quelquesoit la saison et démarre à EPOCH. Comme la rotation de la Terre n’est pas forcément constante, on introduit régulièrement des leap seconds. Depuis EPOCH, on en a introduit 37.

Le temps est envoyé aux ordinateurs depuis des horloges atomiques à travers le protocole NTP. Si il y a des deltas entre le client et le serveur, NTP garantit que les échanges mettent toujours moins de 1 seconde.

Représenter le temps

Pour représenter le temps, on peut utiliser des timestamps. Evidement, ces timestamps s’expriment sur un nombre de bit donné …​ qui sera rempli à EPOCHalypse. Du coup, ça a un impact sur le stockage des dates représentant des instants dans le futur.

On peut aussi utiliser les datetimes ISO (8601). Qui incluent la date, l’heure, et le fuseau horaire.

Enfin, on peut utiliser des dates et heures locaux (sans fuseau horaire). Clairement, il y a beaucoup de non-dits dans ces cas, ce qui n’aide vraiment pas. On peut également dissocier des dates & heures.

Les timezones

Une timezone, c’est un fuseau horaire. Et un timezone offset, c’est le décalage entre un fuseau horaire et UTC. Attention : à partir d’une timezone, on ne peut pas forcément déterminer le timezone offset (par exemple, en France, on a une heure d’été/heure d’hiver).

La plupart des timezone définissent des offsets entiers par rapport à UTC. Ces offsets sont variables par timezone. Et on utilise des TZ Table pour les déterminer.

Les TZ Table sont disponibles sur GitHub, sur un repository où il y a des changements …​ plusieurs fois par semaine.

Comment le système se met-il à jour ?

  • En Java, les TZ Data sont définies dans le JRE (et peuvent être updatées par le TZUpdater – disponible dans le JDK).
  • Pour MySQL, il faut le faire à la main.
  • En Node, on le fait à la main avec un paquet mis à jour à chaque release des TZ Data

Que faire ?

Ca dépend des applications : une application purement française pourra survivre à des mises à jour peu fréquentes. Par contre, pour l’international, il faut pouvoir suivre ces mises à jour rapidement (les russes ont changé leurs TZ Data avec une action effective un mois après).

En particulier, créer des dates dans le futur est dangereux, puisque les règles peuvent changer. Si vous devez le faire, stockez la date et l’heure locale ainsi que la timezone de l’utilisateur (et la date de création).

DST

Le changement d’heure, ça n’est pas pratique (et ça risque de disparaître).

Mais il y a autre chose : quand on passe de l’heure d’hiver à l’heure d’été, une heure n’existe pas. Ca a un impact : que fait votre librairie quand vous donnez une heure qui n’existe pas ? Avec java.util.Date, ça plante.

Réciproquement, au passage à l’heure d’hiver, une heure existe deux fois. Ca n’est pas non plus très pratique. Dans ce cas, le comportement peut aussi être différent selon le navigateur.

Dans les grosses boîtes, les batches qui passent la nuit (à 2H30, par exemple) peuvent avoir des problèmes pénibles. Pour éviter ça, il faut baser les batches sur des heures UTC.

Cas particuliers

En plus de ces éléments …​ curieux, il y a tout un tas de cas particuliers :

  • Les années bissextiles
  • Le 31 décembre d’une année aux îles Samoa n’existe pas
  • Deux dates Java sont égales si elles utilisent le même fuseau horaire. Si ça n’est pas le cas, il ya une méthode isEqual pour ça
  • Et encore, ça n’est rien à côté de la gestion des dates en Javascript, qui semble être authentiquement la fête de la saucisse

Quelques bonnes pratiques

  • Tous les serveurs doivent être en timezone UTC à tous les niveaux
    • La timezone de l’OS doit être UTC
    • La timezone de la DB doit être UTC
  • Envoyer la date n’est pas trivial
    • N’envoyez pas de date sans fuseau horaire
    • N’envoyez pas non plus de date simplement avec la date
    • Envoyez plutôt une range de date (avec la timezone) pour éviter les problèmes louches de changement d’heure
  • En vrai, les recherches de date sont en général des recherches de range …​ Ca mérite d’y réfléchir
  • N’utilisez pas de LocalDateTime !

Time-only patterns

  • Stocker toujours la timezone de l’utilisateur ayant saisi l’heure
  • Evitez de stocker votre heure dans un objet DateTime
    • Utilisez plutôt une chaîne de caractère avec la timezone à côté

Date-only patterns

  • Utilisez une structure adaptée
  • Evitez de stocker une date dans une DateTime. Si vous devez le faire, utilisez midi comme heure, c’est plus facile.
  • Si vous connaissez la timezone, stockez-la

Conclusion

C’était aussi intéressant que ce à quoi je m’attendais, et à mon avis un super complément à l’énorme article de Jon Skeet sur le même sujet. Et en plus, Frédéric était vraiment bon.

Publicités

Répondre

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion /  Changer )

Photo Google

Vous commentez à l'aide de votre compte Google. Déconnexion /  Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion /  Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion /  Changer )

Connexion à %s