Licence CC BY

Les horloges

Dans la vie courante, on utilise une horloge (au sens large du terme) dans deux cas distincts : soit pour connaitre une date, soit pour connaitre une durée, via la différence entre deux mesures sur l’horloge, si on n’a pas de chronomètre1 pour ce faire. C’est pareil en informatique, mais pour des raisons techniques et historiques on a tendance à mélanger tout ça, ce qui peut provoquer des problèmes graves…

Aussi cette partie va essayer de rendre tout ça un peu plus clair. Puis elle abordera le point des planifications et celui de la gestion des horloges dans le cas particulier de l’informatique.


  1. Théoriquement, l’appareil qui sert à mesurer un intervalle de temps entre deux évènements est un chronographe et pas un chronomètre. Néanmoins, comme c’est ce deuxième terme qui est utilisé dans le langage courant, c’est celui que j’emploierai ici.

« Les  » horloges ?

« Les » horloges ? Comment ça, « les » ? Il n’y a qu’une seule horloge, non ?

Eh bien… non, et je ne parle pas de la technologie utilisée. En réalité, deux types d’usages nécessitent deux types d’horloges différents.

Le besoin habituel quand on traite d’horloge, c’est de connaitre la date et l’heure actuelles. Pour ça il faut, eh bien, une horloge qui donne la date et l’heure actuelles. Ça a l’air idiot dit comme ça, mais cette précision a des implications subtiles, mais qui peuvent conduire à des bugs gravissimes si elles sont mal comprises.

Une telle horloge, qui donne donc la date et l’heure qu’il est dans un lieu défini, est l’horloge légale – qui donne donc l’heure légale. Cette heure a la particularité de ne pas être régulière dans le temps. Je reviendrai sur les raisons de cette particularité et ses impacts dans la section dédiée.

Le second usage d’une horloge, c’est de mesurer un intervalle de temps. On a donc besoin d’une fonction de chronomètre qui est rarement nommée ainsi dans les outils informatiques. Pour mesurer une durée précise, on a besoin d’une horloge régulière dans le temps, et on vient de voir que l’horloge légale n’a pas cette propriété. Il nous faut alors un second type d’horloge, appelée horloge monotone, et que je vais détailler dans sa propre section.

L’horloge légale

Définition : l’horloge légale

L’horloge légale donne l’heure légale, donc celle qu’il est officiellement dans un lieu précis.

Elle renvoie une date associée à un fuseau horaire connu, mais parfois non explicite.

Elle est généralement couplée à l’horloge du système.

Ce type d’horloge s’utilise lorsque l’on a besoin d’accéder à une date et une heure légale, c’est-à-dire quand on a besoin de savoir quand est « maintenant ».

Puisque l’horloge légale suit l’heure légale, elle hérite des bizarreries de ce genre de dispositif, comme l’heure d’été, les éventuelles secondes intercalaires ou toute autre implication de la loi sur l’heure légale. Une telle horloge renvoie donc bien une date, mais pas un instant précis.

Comme l’horloge légale est généralement couplée à l’horloge du système, elle en suit les variations. En particulier, si l’heure du système est réglée (manuellement ou à l’aide de NTP), l’heure affichée par l’horloge légale va inclure ces variations.

Ces deux caractéristiques font que rien ne garantit que l’horloge va avancer de manière régulière : toute intervention légale ou de réglage va provoquer des irrégularités. Par exemple, lors du passage de l’heure d’hiver à l’heure d’été, après 01:59:59, il est 03:00:00 – l’horloge saute d’une heure dans le futur. En fait, rien ne garantit que l’horloge légale avance toujours dans le temps. Tous les ans, au passage à l’heure d’hiver, elle passera de 02:59:59 à 02:00:00, et aura donc reculé d’une heure.

D’autre part, l’horloge légale va renvoyer l’heure légale du système où est exécuté le programme – ou parfois tout simplement l’heure UTC – ce qui peut être différent de l’heure utile pour l’usager. Le développeur doit penser à ça et prévoir les conversions idoines, surtout s’il n’a pas la main sur le réglage de cette horloge, comme dans le cas d’un programme exécuté sur un serveur ou dans le cloud.

Les documentations anglophones parlent souvent de wall clock à son sujet.

Une horloge murale électrique
Illustration : une horloge murale électrique. CC BY-SA 3.0 Wissenbourg.

L’horloge monotone

Définition : l’horloge monotone

L’horloge monotone n’est pas une horloge : c’est un chronomètre qui donne un intervalle de temps écoulé depuis un instant de référence.

Elle renvoie une durée.

Elle a une avance régulière et donc indépendante de l’horloge système et de tous les réglages ou fantaisies que cette dernière peut subir.

Ce type d’horloge sert pour toutes les tâches de chronométrage, comme mesurer le temps qu’a pris une action.

L’instant de référence de l’horloge monotone peut être « bien connu » (un repère fixe et universel) ou être totalement arbitraire (par exemple, l’instant de démarrage du programme). Dans le cas d’une horloge monotone dont l’instant de référence est arbitraire, il n’existe pas de moyen simple pour extraire des dates à partir des intervalles qu’elle fournit tant que l’on n’a pas déterminé d’abord la date à laquelle correspond l’instant de référence – ce qui peut ne pas être trivial.

La monotonie de l’horloge garantit que toutes les périodes mesurées seront les durées réelles et seront cohérentes entre elles, indépendamment des perturbations de l’horloge système. Cela évite les bizarreries telles que les durées négatives.

Un chronomètre à main
Illustration : un chronomètre à main. CC BY-SA 3.0 Lesselich.

Le cas particulier des planifications

Une planification de tâche correctement utilisée nécessite de jongler avec les deux types d’horloges et les fuseaux horaires :

  • L’horloge légale pour lancer les tâches à l’heure prévue ;
  • L’horloge monotone pour exécuter les tâches aux intervalles de temps voulus, et pour gérer les incohérences de l’horloge légale.

Admettons que je programme une sauvegarde tous les jours à 2 h 30 du matin.

  • Si je ne me base que sur l’heure légale et mon fuseau horaire réel :
    • Lors du passage à l’heure d’hiver, elle va être lancée deux fois, parce que l’horloge légale remonte de 02:59:59 à 02:00:00
    • Lors du passage à l’heure d’été, elle ne va pas être lancée du tout, parce que l’horloge légale saute de 01:59:59 à 03:00:00
  • Si je lance mes planifications à partir d’une horloge UTC, l’heure légale d’exécution va être décalée d’une heure pendant la moitié de l’année si l’utilisateur habite un lieu où s’applique une heure d’été (selon le moment où il a créé sa planification)1.
  • Si je lance mes programmes à partir de la seule horloge monotone, ça peut être difficile de savoir quand les lancer si celle-ci n’a pas de repère d’origine fixe.

Ajoutons à ça les difficultés habituelles des planificateurs, comme :

  • la gestion des dépendances entre tâches ;
  • la gestion des collisions entre tâches (parce que l’occurrence précédente n’est pas finie, car trop longue ou démarrée à la main) ;
  • la gestion des tâches qui auraient dû être exécutées, mais qui ne l’étaient pas parce que le planificateur n’était pas lancé.

Et on en arrive à cette conclusion :

Ne créez pas votre propre système de planification. Trouvez-en un qui est connu pour fonctionner2 et que vous pouvez utiliser directement, ça vous évitera de belles prises de tête.

Un tableau de planification à post-its
Illustration : un tableau de planification de tâches, toujours plus efficace qu’un système informatique mal conçu. CC BY-SA 4.0 Ciell.

  1. Un exemple de ce problème dans le monde réel : si vous avez un aspirateur robot de chez Ecovacs, ses tâches planifiées sont en réalité rattachées à des heures sur le fuseau horaire de Chine – c’est visible à un endroit dans l’interface – et donc se décaleront d’une heure aux changements d’horaires. Ainsi, la tâche que j’avais planifiée « juste après mon départ du boulot » s’est lancée « pendant le petit déjeuner »…
  2. Parce que certains planificateurs sont connus pour ne pas gérer correctement les problématiques susmentionnées, comme le planificateur Java IBM en 2010.

La gestion des horloges en informatique

Un peu de préparation

La première étape est d’identifier le type d’horloge dont vous avez réellement besoin.

La seconde étape, c’est de trouver comment manipuler le type d’horloge voulu dans votre langage de programmation, et là les choses peuvent se compliquer. La différence entre les deux types d’horloges est souvent mal comprise, et les concepts peuvent être mal nommés, voire complètement absents de certains langages ou de leurs vieilles versions.

En particulier, les horloges monotones sont parfois inexistantes ou d’accès peu intuitif.

Comment trouver la documentation de l’horloge monotone dans votre langage

Essayer de rechercher le nom de votre langage plus :

  • monotonic clock,
  • high resolution time,
  • ou steady clock

Et dans tous les cas vérifiez dans la documentation officielle que ce que vous avez trouvé correspond bien à ce que vous cherchez !

Les annexes contiennent des liens vers la doc d’horloges monotones dans divers langages.

Vérifiez que vous utilisez les bonnes méthodes : beaucoup de langages ont « récemment » implémenté de nouvelles fonctionnalités pour gérer plus proprement et facilement toutes les subtilités susmentionnées. Une documentation ancienne pourrait vous laisser employer des méthodes obsolètes.

Pensez à vérifier l’unité d’intervalle de temps manipulée par votre horloge ainsi que sa précision réelle. Cette dernière peut être très différente de l’unité et varier selon le contexte. Par exemple, en JavaScript, l’horloge monotone renvoie des portions de millisecondes, mais la précision réelle peut être aussi mauvaise que 100 ms.

Les pièges à éviter

Le contexte utilisé par l’horloge légale

L’horloge légale peut renvoyer des valeurs différentes selon le contexte qu’on lui passe, en particulier le fuseau horaire désiré. D’autre part, si rien n’est précisé, la date renvoyée peut être dépendante du serveur. Par exemple en Java :

// Renvoie « maintenant », la date locale sur le fuseau horaire par défaut du serveur
LocalDateTime.now(); // En explicitant le fuseau horaire
DateTime.now();      // Avec fuseau horaire implicite
// Renvoie « maintenant », la date locale, sur le fuseau horaire UTC
LocalDateTime.now(Clock.systemUTC()); // En explicitant le fuseau horaire
DateTime.now(Clock.systemUTC());      // Avec fuseau horaire implicite
// « Maintenant » au Japon, de manière implicite
DateTime.now(ZoneId.of("JST"));
// Renvoie « maintenant », sous la forme d’un instant et pas d’une date
Instant.now();              // En tant qu’objet directement manipulable
System.currentTimeMillis(); // En tant que valeur de timestamp (à éviter)

Le système de dates et d’horloges de Java est particulièrement complet, votre langage ne permettra peut-être pas autant de subtilités.

La manipulation des horloges monotones

Le principal piège ici est que, dans l’immense majorité des cas, ce que renvoie une horloge monotone n’est pas une date. Il est donc impossible d’utiliser l’arithmétique et les conversions de dates immédiatement sur les retours de ces horloges.

Il est souvent indispensable de faire une soustraction entre deux appels à ce type d’horloge pour en déduire une durée que l’on pourra manipuler comme telle, les valeurs renvoyées par l’horloge n’ayant pas de sens pratique directement employable.

Par exemple en Java :

long start = System.nanoTime();
var out = maMethodeLente();
System.out.println("maMethodeLente a été exécutée en " + ((System.nanoTime() - start) / 1_000_000.0 + " ms");
return out;

On a deux systèmes différents apparentés à une horloge à notre disposition :

  • L’horloge légale, qui permet de savoir quand est « maintenant » et renvoie une date, sans garantie d’avance régulière.
  • L’horloge monotone, qui est en réalité un chronomètre qui progresse régulièrement mais qui ne retourne généralement pas une date utilisable.

Les horloges en informatique sont souvent utilisées pour des tâches récurrentes ou de planification, ce qui est un exercice délicat : vous devriez toujours employer un planificateur tiers.

Enfin, manipuler les horloges en informatique est souvent assez simple, tant qu’on vérifie que l’on recourt aux méthodes adaptées au besoin et qu’on leur passe les bons paramètres.