Quelques remarques sur la gestion des données temporelles

Je viens de lire cet excellent article sur des hypothèses fausses (parfois de manière étonnante) que les programmeurs font sur le temps et sa gestion informatisée. Quelques-unes sont très simples, comme le fait que Février n’a pas toujours 28 jours, mais d’autres sont plus complexes.

Saviez-vous par exemple que tous les jours ne durent pas 24 heures ?

Cet article recense plein de problèmes possibles sur la gestion du temps, mais à sa lecture, je me disais qu’il ne proposait pas beaucoup de solution sur des exemples concrets. Du coup, je me disais que ça vaudrait le coup de lister les astuces et méthodes pour éviter ces problèmes. Je commence la liste :

Utiliser DateTime et TimeSpan

… et ce de manière correcte, bien entendu. On commence par un exemple bateau de la mauvaise façon de calculer le nombre de jours entre deux dates :

[TestMethod]
public void MauvaiseFacon()
{
    DateTime now = DateTime.Now;
    DateTime then = new DateTime(1974, 12, 25);

    int nbJours = 365 * (now.Year - then.Year)
        + 30 * (now.Month - then.Month)
        + (now.Day - then.Day);
    Assert.AreEqual(13692, nbJours);
}

Il faut bien entendu tenir compte des années bissextiles, mais saviez-vous par exemple que le mode de calcul de celle-ci est le suivant :

  1. L’année doit être un multiple de 4
  2. Elle ne doit pas être un multiple de 100
  3. Sauf dans le cas où elle est un multiple de 400

Afin de s’éviter toute cette complexité, le plus simple est donc bien sûr d’écrire plutôt le code comme ceci :

[TestMethod]
public void FaconCorrecte()
{
    DateTime now = DateTime.Now;
    DateTime then = new DateTime(1974, 12, 25);

    TimeSpan ecart = now - then;
    int nbJours = ecart.Days;
    Assert.AreEqual(13692, nbJours);
}

Le résultat est le suivant :

image

Ceci est l’occasion de faire la remarque que ces tests ne sont pas du tout indépendants du contexte, car ils seront faux dès demain, où le nombre de jours a augmenté. C’est pour montrer ce problème que j’ai pris une des deux dates de manière non fixe.

Comprendre la différence entre date locale et date UTC

Dans les API de .NET, il est également possible de gérer les dates et heures UTC. En gros, l’idée du temps universel est de dire qu’un même moment correspond à des heures différentes d’un fuseau horaire à l’autre.

Par exemple, à ce jour en France, nous sommes à l’heure d’été, et donc 2 heures après le temps universel :

[TestMethod]
public void TestUTC()
{
    DateTime now = DateTime.Now;
    DateTime nowUTC = DateTime.UtcNow;

    TimeSpan ecart = now - nowUTC;
    Assert.AreEqual(2, ecart.Hours);
}

Pour bien comprendre toute la richesse de la gestion du temps en .NET, il faut jeter un œil à la documentation de System.Globalization.DateTimeFormatInfo : 20 méthodes, 28 propriétés, ça peut paraitre beaucoup pour juste gérer les formats de date, mais on a accès à l’ère, au type de calendrier (Julien, Grégorien, etc.) avec des classes JulianCalendar et GregorianCalendar dédiée.

Même dans le calendrier Grégorien, on a la possibilité de choisir un type particulier :

image

Du coup, attention à bien choisir le type précis dont vous avez besoin, car l’API a une énorme richesse, et il y a une bonne raison pour cela : c’est que la gestion du temps est, contrairement à ce qu’on peut croire, un sujet extrêmement complexe. En tapant DateTimeOffset dans un moteur de recherche, vous trouverez plein de bonnes ressources, en particulier sur cet excellent site qu’est StackOverflow.

Synchroniser les horloges

Un autre cas appliqué où il est nécessaire de très bien gérer le temps est dans les Message Oriented Middleware. Lorsque des messages asynchrones sont échangés sur un SI, un timestamp est systématiquement appliqué pour régler les problèmes de durée de vie, etc. Or, ce timestamp est nécessairement appliqué sur la machine émettrice, et lue sur les machines destinataires.

Ne pas avoir la même heure sur les différentes machines composant un ESB est donc absolument essentiel, et ce de manière très précise : quelques minutes suffisent à perdre des messages. Heureusement, la plupart des OS permettent de synchroniser très facilement une horloge sur celle d’un autre ordinateur. Par exemple, en Windows :

net time \\machine /set

Se baser sur un serveur de temps

Pour aller encore plus loin, l’idéal est de synchroniser toutes les machines du domaine (ce qu’on peut faire avec net time), voire même synchroniser toutes les machines du monde, ce qui est la raison pour laquelle les horloges atomiques de référence existent.

Dans le cas de Windows, c’est visiblement le cas par défaut, en tout cas sur Windows 7 Ultimate 64 bits :

image

Conclusion

La gestion du temps est bien plus complexe que ce qu’on peut imaginer, et même dans les cas où on pense être sur un calcul simple, il faut bien utiliser les outils dédiés qui suivent les normes.

About JP Gouigoux

Jean-Philippe Gouigoux est Architecte Logiciel, MVP Connected Systems Developer. Il intervient régulièrement à l'Université de Bretagne Sud ainsi qu'à l'Agile Tour. Plus de détails sur la page "Curriculum Vitae" de ce blog.
This entry was posted in C#. Bookmark the permalink.

One Response to Quelques remarques sur la gestion des données temporelles

  1. Très bonne idée d’ecrir sur ce sujet!

    Qu’est-ce que, j’ai pu pesté par le passé sur des personnes qui réinventaient la roue au lieur d’utiliser les classes intégrées à .net depuis des lustres…

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Captcha Captcha Reload