Secondes intercalaires (leap seconds)#
Pourquoi#
Un serveur Stratum 1 ne se contente pas de suivre une horloge qui avance régulièrement : il doit aussi savoir qu’une fois tous les quelques années, une seconde supplémentaire s’insère dans le calendrier civil. Ignorer ce mécanisme, ou le gérer avec un fichier de données périmé, produit un décalage d’une seconde entière, une éternité à l’échelle de précision visée par ce projet (autour de la microseconde). Ce chapitre explique d’où viennent les secondes intercalaires et comment ce projet automatise leur prise en compte de façon robuste.
D’où viennent les secondes intercalaires#
Trois échelles de temps coexistent, avec des règles de progression différentes :
| Échelle | Base | Comportement |
|---|---|---|
| TAI (Temps Atomique International) | Moyenne pondérée de plus de 400 horloges atomiques au césium, réparties dans ~80 laboratoires nationaux | Monotone, strictement croissante, jamais de saut |
| UT1 (Temps Universel Astronomique) | Rotation réelle de la Terre, mesurée par interférométrie sur des quasars | Ralentit progressivement (effet de marée lunaire), avec des variations irrégulières |
| UTC (Temps Universel Coordonné) | Échelle civile légale | Reste proche d’UT1 (écart < 0,9 s) tout en bénéficiant de la stabilité du TAI |
La Terre tourne un peu moins vite qu’au moment où la seconde a été définie, un écart minime, mais qui s’accumule. Pour que UTC (l’heure légale que tout le monde utilise) ne dérive jamais de plus de 0,9 seconde par rapport à la rotation réelle de la Terre, l’IERS (International Earth Rotation and Reference Systems Service) insère périodiquement une seconde intercalaire, toujours le 30 juin ou le 31 décembre à 23:59:59 UTC, quand elle est nécessaire.
Depuis la dernière seconde intercalaire (1er janvier 2017), l’écart TAI − UTC = 37 secondes. Cette valeur ne bouge que par paliers d’une seconde entière, annoncés à l’avance par l’IERS via le “Bulletin C”.
Décision majeure pour l’avenir (résolution 4 de la CGPM, 2022) : à partir de 2035, la tolérance UTC-UT1 sera assouplie et les secondes intercalaires seront gelées à leur valeur, un changement de paradigme international après plus de 50 ans de leap seconds, motivé par les difficultés que ces sauts imprévisibles posent aux systèmes informatiques modernes. Voir la résolution 4 de la CGPM.
Comment le GNSS et chrony gèrent cet écart#
Le temps GPS (GPS Time) est, comme le TAI, continu : il ne subit jamais de seconde intercalaire. Actuellement, GPS Time = UTC + 18 secondes. Le récepteur GNSS reçoit la correction UTC courante directement dans le message de navigation diffusé par les satellites (sous-trame 4 du message GPS), rafraîchie plusieurs heures avant chaque échéance potentielle.
Côté serveur, chrony a besoin de sa propre source d’information sur
cet écart, via un fichier
leap-seconds.list
publié par l’IANA/IERS :
# Dans chrony.conf
leapseclist /etc/chrony/leap-seconds.listCe fichier contient, entre autres, une date d’expiration, au-delà de laquelle chrony ne peut plus garantir que la correction est à jour, et le signale.
Mise à jour automatisée et validée#
cat > /usr/local/sbin/leap-seconds-update <<'EOF'
#!/bin/bash
# Mise à jour VALIDÉE de /etc/chrony/leap-seconds.list.
# Installation + restart chrony UNIQUEMENT si le contenu a réellement changé.
set -euo pipefail
URL="https://data.iana.org/time-zones/data/leap-seconds.list"
DST="/etc/chrony/leap-seconds.list"
NTP_EPOCH_OFFSET=2208988800 # 1900-01-01 -> 1970-01-01
log() { logger -t leap-seconds "$1"; }
fail() { log "ERREUR : $1"; exit 1; }
TMP=$(mktemp /tmp/leap-seconds.XXXXXX)
trap 'rm -f "$TMP"' EXIT
curl -fsSL --max-time 60 "$URL" -o "$TMP" || fail "téléchargement impossible"
# a. Validation structurelle (présence des lignes clés)
grep -q '^#\$' "$TMP" || fail "ligne #\$ (dernière MAJ) absente"
grep -q '^#@' "$TMP" || fail "ligne #@ (expiration) absente"
grep -q '^#h' "$TMP" || fail "ligne #h (hash) absente"
# b. Le fichier téléchargé n'est pas lui-même déjà expiré
EXPIRY_NTP=$(awk '/^#@/ {print $2; exit}' "$TMP")
EXPIRY_UNIX=$((EXPIRY_NTP - NTP_EPOCH_OFFSET))
[ "$EXPIRY_UNIX" -gt "$(date +%s)" ] || fail "fichier téléchargé déjà expiré"
# c. Intégrité : hash SHA-1 embarqué recalculé et comparé
STORED=$(awk '/^#h/ { for (i=2; i<=NF; i++) printf "%08s", $i; exit }' "$TMP" | tr ' ' '0')
COMPUTED=$( {
awk '/^#\$/ {printf "%s", $2; exit}' "$TMP"
awk '/^#@/ {printf "%s", $2; exit}' "$TMP"
sed 's/#.*$//' "$TMP" | awk 'NF >= 2 {printf "%s%s", $1, $2}'
} | sha1sum | cut -d' ' -f1 )
[ "$STORED" = "$COMPUTED" ] || fail "hash SHA-1 invalide"
# Installation seulement si le contenu a changé
if cmp -s "$TMP" "$DST"; then
log "aucun changement (expire le $(date -u -d "@$EXPIRY_UNIX" +%F))"
exit 0
fi
install -o root -g root -m 0644 "$TMP" "$DST"
log "nouveau fichier installé, restart chrony"
systemctl restart chrony # leapseclist n'est lu qu'au démarrage
EOF
chmod +x /usr/local/sbin/leap-seconds-update
cat > /etc/cron.d/leap-seconds <<'EOF'
17 3 1 * * root /usr/local/sbin/leap-seconds-update
EOFLe décalage 17 3 (3h17, plutôt qu’une heure ronde comme minuit ou 3h00)
évite de faire coïncider cette tâche avec d’autres jobs cron planifiés
sur des horaires ronds, une convention courante pour répartir la charge
plutôt qu’une valeur arbitraire. Le premier jour du mois (1) donne une
fréquence mensuelle, largement suffisante face à un fichier qui change au
mieux deux fois par an.
Erreurs à éviter#
Un simple
curlsans validation peut écraser un fichier valide par une page d’erreur. Si le serveur distant est temporairement indisponible ou renvoie une page d’erreur CDN, un script naïf (curl -o /etc/chrony/leap-seconds.list ...) écrase silencieusement un fichier fonctionnel par du contenu invalide, chrony échouera alors à interpréter le fichier au prochain redémarrage, potentiellement bien après l’incident de téléchargement, rendant le diagnostic difficile. Toujours télécharger dans un fichier temporaire, valider avant d’installer, et ne remplacer le fichier en place qu’après validation complète.
- Redémarrer chrony à chaque exécution du cron, même sans changement.
Le fichier
leap-seconds.listchange au mieux deux fois par an, souvent moins. Unsystemctl restart chronyinconditionnel à chaque exécution périodique casse inutilement la boucle de discipline d’horloge en cours (cf. chapitre Chrony), ne redémarrer que lorsque le contenu a effectivement changé (cmp -s) est la bonne pratique. - Exécuter la mise à jour trop rarement. Une fréquence de mise à jour de “deux fois par an, en espérant que ça tombe juste” signifie qu’un échec de téléchargement ponctuel (panne réseau temporaire) n’est retenté que six mois plus tard, largement après l’expiration potentielle du fichier. Une fréquence mensuelle avec détection d’absence de changement (donc pas de coût en cas d’échec de téléchargement retenté) est un bien meilleur compromis.
- Oublier que
leapseclistn’est lu qu’au démarrage de chronyd. Contrairement au rechargement de certificat TLS (chapitre NGINX/NTS), qui peut se faire à chaud viaSIGHUP, un nouveau fichierleap-seconds.listnécessite un redémarrage complet du démon pour être pris en compte, d’où l’utilité de ne le faire que lorsque c’est vraiment nécessaire (point précédent).
Vérifier#
chronyc tracking | grep "Leap status"
# Doit retourner "Normal" en dehors des 24h précédant une seconde intercalaire
# Date d'expiration du fichier actuellement chargé
awk '/^#@/ {print $2}' /etc/chrony/leap-seconds.list
# Test manuel du script (doit logger "aucun changement" si déjà à jour)
/usr/local/sbin/leap-seconds-update
journalctl -t leap-seconds -n 5📚 Pour aller plus loin
- Les règles régissant UTC et les secondes intercalaires sont définies par l’UIT (Union Internationale des Télécommunications), recommandation ITU-R TF.460-6.
- Les annonces officielles de secondes intercalaires sont publiées par l’IERS via son Bulletin C, disponible sur iers.org.
- La décision de geler les secondes intercalaires à partir de 2035 a été adoptée par la Conférence Générale des Poids et Mesures (CGPM), résolution 4 de 2022, un changement historique après plus de 50 ans de pratique.
- Le format et le calcul de la correction GPS Time → UTC (paramètres ΔtLS) sont spécifiés dans IS-GPS-200, sous-trame 4, page 18 du message de navigation.