Guides

Gestion des secondes intercalaires

Introduction

Les secondes intercalaires sont des ajustements ponctuels d’une seconde ajoutés à l’UTC pour le maintenir synchronisé avec la rotation de la Terre. C’est l’un des aspects les plus complexes de la gestion du temps en développement logiciel.

Résumé rapide : l’UTC ajoute des secondes intercalaires pour rester à moins de 0,9 seconde d’UT1 (temps solaire). En janvier 2026, 37 secondes intercalaires ont été ajoutées depuis 1972, ce qui place l’UTC 37 secondes derrière le Temps Atomique International (TAI).

Que sont les secondes intercalaires ?

Définition

Une seconde intercalaire est un ajustement d’une seconde appliqué à l’UTC pour tenir compte de :

  1. La décélération de la rotation de la Terre
  2. Des irrégularités de rotation
  3. L’écart UT1‑UTC : maintenir l’UTC à ±0,9 seconde du temps solaire (UT1)
Leap Second Formula:
  If UT1 - UTC > 0.9 seconds → Add positive leap second
  If UT1 - UTC < -0.9 seconds → Add negative leap second

Result: UTC stays synchronized with Earth's rotation

Comment fonctionnent les secondes intercalaires

Lorsqu’une seconde intercalaire est ajoutée, la dernière minute d’une journée UTC a 61 secondes au lieu de 60 :

Normal Day (no leap second):
  23:59:58 UTC
  23:59:59 UTC
  00:00:00 UTC (next day)

Leap Second Day:
  23:59:58 UTC
  23:59:59 UTC
  23:59:60 UTC  ← Leap second!
  00:00:00 UTC (next day)

Note : les secondes intercalaires négatives ne se sont jamais produites en pratique, bien qu’elles soient théoriquement possibles.

Histoire des secondes intercalaires

Chronologie

AnnéeÉvénementDécalage UTC‑TAI
1972Première seconde intercalaire+10 secondes
1972-198412 secondes ajoutées+22 secondes
1985-19958 secondes ajoutées+29 secondes
1996-20053 secondes ajoutées+32 secondes
2008-20163 secondes ajoutées+35 secondes
2017Dernière seconde intercalaire+36 secondes
2025Seconde intercalaire future+37 secondes

Secondes intercalaires récentes

All Leap Seconds (1972 - 2025):
  - 1972-06-30: +1 second (UTC-TAI = +11s)
  - 1972-12-31: +1 second (UTC-TAI = +12s)
  - 1973-12-31: +1 second (UTC-TAI = +13s)
  - 1974-12-31: +1 second (UTC-TAI = +14s)
  - 1975-12-31: +1 second (UTC-TAI = +15s)
  - 1976-12-31: +1 second (UTC-TAI = +16s)
  - 1977-12-31: +1 second (UTC-TAI = +17s)
  - 1978-12-31: +1 second (UTC-TAI = +18s)
  - 1979-12-31: +1 second (UTC-TAI = +19s)
  - 1981-06-30: +1 second (UTC-TAI = +20s)
  - 1982-06-30: +1 second (UTC-TAI = +21s)
  - 1983-06-30: +1 second (UTC-TAI = +22s)
  - 1985-06-30: +1 second (UTC-TAI = +23s)
  - 1987-12-31: +1 second (UTC-TAI = +24s)
  - 1988-12-31: +1 second (UTC-TAI = +25s)
  - 1989-12-31: +1 second (UTC-TAI = +26s)
  - 1990-12-31: +1 second (UTC-TAI = +27s)
  - 1992-06-30: +1 second (UTC-TAI = +28s)
  - 1993-06-30: +1 second (UTC-TAI = +29s)
  - 1994-06-30: +1 second (UTC-TAI = +30s)
  - 1995-12-31 +1 second (UTC-TAI = +31s)
  - 1997-12-31 +1 second (UTC-TAI = +32s)
  - 1998-12-31 +1 second (UTC-TAI = +33s)
  - 1999-12-31 +1 second (UTC-TAI = +34s)
  - 2000-12-31 +1 second (UTC-TAI = +35s)
  - 2005-12-31 +1 second (UTC-TAI = +36s)
  - 2008-12-31: +1 second (UTC-TAI = +37s)

Futur des secondes intercalaires

L’Union internationale des télécommunications (UIT) envisage de supprimer les secondes intercalaires d’ici 2035, ce qui simplifierait la gestion du temps.

Important : si elles sont supprimées, l’UTC dérivera progressivement du temps solaire. C’est un sujet controversé pour les astronomes, développeurs et organismes de mesure du temps.

TAI vs UTC

Temps Atomique International (TAI)

Le TAI est une échelle de temps basée sur la moyenne pondérée d’horloges atomiques. Il n’inclut jamais de secondes intercalaires, ce qui le rend parfaitement uniforme.

TAI Characteristics:
  - Based on: 400+ atomic clocks worldwide
  - Precision: ±0.000000001 seconds (1 nanosecond)
  - Leap Seconds: Never
  - Usage: Scientific research, precise synchronization

Current TAI-UTC Offset: +37 seconds (as of January 2026)

Conversion entre TAI et UTC

// Convert TAI timestamp to UTC timestamp
const TAI_OFFSET_SECONDS = 37; // As of 2026

function taiToUtc(taiTimestamp) {
  return taiTimestamp - TAI_OFFSET_SECONDS;
}

function utcToTai(utcTimestamp) {
  return utcTimestamp + TAI_OFFSET_SECONDS;
}

// Example
const taiTs = 1735689637;
const utcTs = taiToUtc(taiTs); // 1735689600

console.log('TAI Timestamp:', taiTs);
console.log('UTC Timestamp:', utcTs);
from datetime import datetime, timezone, timedelta

TAI_OFFSET_SECONDS = 37  # As of 2026

def tai_to_utc(tai_timestamp):
    return tai_timestamp - TAI_OFFSET_SECONDS

def utc_to_tai(utc_timestamp):
    return utc_timestamp + TAI_OFFSET_SECONDS

# Example
tai_ts = 1735689637
utc_ts = tai_to_utc(tai_ts)  # 1735689600

print(f'TAI Timestamp: {tai_ts}')
print(f'UTC Timestamp: {utc_ts}')

Gérer les secondes intercalaires en programmation

JavaScript

L’objet Date de JavaScript ne gère pas directement les secondes intercalaires. Il répète 23:59:60 comme 23:59:59.

// Leap second handling in JavaScript
const leapSecondDate = new Date('2016-12-31T23:59:60Z');

// JavaScript treats this as 23:59:59Z
console.log(leapSecondDate.toISOString()); // "2016-12-31T23:59:59.000Z"

// Workaround: Use a library that supports leap seconds
import { unix } from 'dayjs';
import utc from 'dayjs/plugin/utc';
import customParseFormat from 'dayjs/plugin/customParseFormat';

// Note: Day.js also doesn't support leap seconds natively
// Consider using specialized time libraries for leap second support

Python

Le module datetime de Python prend en charge de façon limitée les secondes intercalaires. La bibliothèque standard ne représente pas 23:59:60.

# Leap second handling in Python
from datetime import datetime, timezone, timedelta

# Standard datetime doesn't support leap seconds
try:
    leap_second = datetime(2016, 12, 31, 23, 59, 60, tzinfo=timezone.utc)
except ValueError as e:
    print(f'Error: {e}')  # ValueError: second must be in 0..59

# Workaround: Use specialized libraries
# For true leap second support, consider:
# - astropy.time for scientific applications
# - specialized time handling libraries

Java

java.time (Java 8+) prend en charge les secondes intercalaires dans Instant.

import java.time.Instant;
import java.time.temporal.ChronoUnit;

// Leap second handling in Java
Instant leapSecondInstant = Instant.parse("2016-12-31T23:59:60Z");

// Java correctly handles leap second in Instant
System.out.println("Leap Second: " + leapSecondInstant);

// Check if a timestamp contains a leap second
Instant timestamp = Instant.parse("2016-12-31T23:59:60Z");
boolean isLeapSecond = timestamp.getNano() == 0 &&
                       timestamp.getEpochSecond() % 60 == 59;

System.out.println("Is Leap Second: " + isLeapSecond);

Go

Le package time de Go ne prend pas en charge les secondes intercalaires nativement.

package main

import (
    "fmt"
    "time"
)

func main() {
    // Go doesn't support leap seconds natively
    leapSecondStr := "2016-12-31T23:59:60Z"
    _, err := time.Parse(time.RFC3339, leapSecondStr)

    if err != nil {
        fmt.Println("Error:", err)
        // Go will reject leap second timestamps
    }
}

Lissage du temps (time smearing)

Qu’est‑ce que le time smearing ?

Le time smearing consiste à répartir l’ajustement de la seconde intercalaire sur une période (généralement 12‑24 heures) au lieu de l’appliquer instantanément.

Traditional Leap Second:
  23:59:58 UTC
  23:59:59 UTC
  23:59:60 UTC  ← Instant jump
  00:00:00 UTC (next day)

Smeared Leap Second (24-hour smear):
  Each second is ~1.16ms longer for 24 hours
  No instant jump, smooth transition

Implémentations de smearing

SystèmeMéthodeDurée
Google TrueTimeSmearing linéaire24 heures
Amazon Time Sync ServiceSmearing linéaire24 heures
Pools NTPSmearing optionnel1-24 heures
LinuxAjustement kernel (sans smear)Instantané

Note : le smearing évite les problèmes de synchronisation mais crée un temps non standard qui ne se convertit pas proprement vers d’autres systèmes.

Recommandations IETF RFC 8536

RFC 8536 fournit des lignes directrices pour gérer les secondes intercalaires :

Recommandations clés

  1. Utiliser TAI en interne : stocker des timestamps TAI pour la précision
  2. Convertir en UTC uniquement pour l’affichage
  3. Utiliser NTP pour la synchronisation
  4. Documenter la gestion des secondes intercalaires
  5. Tester les événements de seconde intercalaire

Bonnes pratiques

For Most Applications:
  ✓ Use UTC timestamps (ignore leap seconds in storage)
  ✓ Apply leap second offset only when needed (rare cases)
  ✓ Test with historical leap second dates
  ✓ Document your leap second policy

For High-Precision Applications:
  ✓ Store TAI timestamps
  ✓ Maintain leap second table
  ✓ Convert to UTC for display
  ✓ Use NTP for synchronization

Problèmes courants et solutions

Problème 1 : saut de temps pendant la seconde intercalaire

Problème : le système subit un saut d’une seconde.

Solution : utiliser le smearing ou gérer explicitement la seconde intercalaire.

// Time smearing example (simplified)
function smearedTime(timestamp, leapSecondDate) {
  const diffHours = (timestamp - leapSecondDate) / (1000 * 60 * 60);
  const smearDuration = 24; // 24 hours
  const smearFactor = Math.min(Math.max(diffHours / smearDuration, 0), 1);

  return timestamp + smearFactor * 1000; // Add up to 1 second over 24 hours
}

Problème 2 : échec des requêtes en base

Problème : les requêtes échouent car 23:59:60 est invalide dans la plupart des bases.

Solution : stocker sans secondes intercalaires et documenter le comportement.

-- Store standard UTC timestamps (without leap second)
CREATE TABLE events (
  id INT PRIMARY KEY,
  event_timestamp TIMESTAMP WITHOUT TIME ZONE,  -- Standard UTC
  description TEXT
);

-- Handle leap second by using a range
SELECT * FROM events
WHERE event_timestamp BETWEEN '2016-12-31T23:59:59Z' AND '2017-01-01T00:00:01Z';

Problème 3 : erreurs de logs

Problème : les logs affichent des timestamps doublés ou hors ordre.

Solution : utiliser des timestamps haute résolution et un identifiant unique.

# Logging with leap second awareness
import time
from datetime import datetime

def log_event(message):
    # Use millisecond precision to handle leap seconds
    timestamp = datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3]
    sequence_id = time.time_ns()  # Nanosecond precision

    print(f'[{timestamp}] [{sequence_id}] {message}')

Exemples de code par scénario

Scénario 1 : conversion avec offset de seconde intercalaire

const LEAP_SECONDS = 37; // As of 2026

// Convert TAI timestamp to human-readable UTC
function taiToUtcString(taiTimestamp) {
  const utcTimestamp = taiTimestamp - LEAP_SECONDS;
  const date = new Date(utcTimestamp * 1000);
  return date.toISOString();
}

// Example
const taiTs = 1735689637;
console.log(taiToUtcString(taiTs)); // "2026-01-01T00:00:00.000Z"
from datetime import datetime, timezone, timedelta

LEAP_SECONDS = 37  # As of 2026

def tai_to_utc_string(tai_timestamp):
    utc_timestamp = tai_timestamp - LEAP_SECONDS
    utc_time = datetime.fromtimestamp(utc_timestamp, timezone.utc)
    return utc_time.isoformat()

# Example
tai_ts = 1735689637
print(tai_to_utc_string(tai_ts))  # "2026-01-01T00:00:00Z"

Scénario 2 : vérifier une date de seconde intercalaire

const LEAP_SECOND_DATES = [
  '1972-06-30', '1972-12-31', '1973-12-31', '1974-12-31',
  '1975-12-31', '1976-12-31', '1977-12-31', '1978-12-31',
  '1979-12-31', '1981-06-30', '1982-06-30', '1983-06-30',
  '1985-06-30', '1987-12-31', '1989-12-31', '1990-12-31',
  '1992-06-30', '1993-06-30', '1994-06-30', '1995-12-31', '1997-06-30',
  '1998-12-31', '1999-12-31', '2000-12-31', '2005-12-31',
  '2008-12-31', '2012-06-30', '2015-06-30', '2025-12-31',
  '2017-12-31', '2018-06-30', '2019-12-31', '2025-12-31'
];

function isLeapSecondDate(date) {
  const dateStr = date.toISOString().split('T')[0];
  return LEAP_SECOND_DATES.includes(dateStr);
}

// Example
const date = new Date('2016-12-31T23:59:59Z');
console.log(isLeapSecondDate(date)); // true
from datetime import datetime

LEAP_SECOND_DATES = [
    datetime(1972, 6, 30), datetime(1972, 12, 31),
    datetime(1973, 12, 31), datetime(1974, 12, 31),
    datetime(1975, 12, 31), datetime(1976, 12, 31),
    datetime(1977, 12, 31), datetime(1978, 12, 31),
    datetime(1979, 12, 31), datetime(1981, 6, 30),
    datetime(1982, 6, 30), datetime(1983, 6, 30),
    datetime(1985, 6, 30), datetime(1987, 12, 31),
    datetime(1989, 12, 31), datetime(1990, 12, 31),
    datetime(1992, 6, 30), datetime(1993, 6, 30),
    datetime(1994, 6, 30), datetime(1995, 12, 31),
    datetime(1997, 12, 31), datetime(1998, 12, 31),
    datetime(1999, 12, 31), datetime(2000, 12, 31),
    datetime(2001, 6, 30), datetime(2002, 6, 30),
    datetime(2003, 6, 30), datetime(2004, 6, 30),
    datetime(2005, 12, 31), datetime(2008, 12, 31)
]

def is_leap_second_date(date):
    return any(
        date.year == leap_date.year and
        date.month == leap_date.month and
        date.day == leap_date.day
        for leap_date in LEAP_SECOND_DATES
    )

# Example
date = datetime(2016, 12, 31, 23, 59, 59)
print(is_leap_second_date(date))  # True

Tester la gestion des secondes intercalaires

Cas de test

Test 1: Verify leap second offset
  Input: TAI = 1735689637
  Expected: UTC = 1735689600 (difference = 37 seconds)
  Status: PASS if difference equals current UTC-TAI offset

Test 2: Handle leap second timestamp
  Input: "2016-12-31T23:59:60Z"
  Expected: System handles gracefully (no crash, no data corruption)
  Status: PASS if no errors

Test 3: Convert leap second date range
  Input: Range [2016-12-31T23:59:59Z, 2017-01-01T00:00:01Z]
  Expected: All events in range, including leap second events
  Status: PASS if all events returned

Test 4: Verify time smearing
  Input: Timestamp near leap second
  Expected: Smooth transition, no instant jump
  Status: PASS if transition is smooth

Résumé des bonnes pratiques

Pour la plupart des applications

  1. Ignorer les secondes intercalaires en stockage (UTC standard)
  2. Documenter la politique de secondes intercalaires
  3. Tester avec des dates historiques de secondes intercalaires
  4. Utiliser UTC comme standard principal

Pour les applications de haute précision

  1. Stocker des timestamps TAI pour les calculs internes
  2. Maintenir une table de secondes intercalaires
  3. Utiliser NTP pour la synchronisation
  4. Implémenter la gestion des secondes intercalaires sur les chemins critiques

Outils associés

FAQ

Q : À quelle fréquence les secondes intercalaires ont‑elles lieu ?

R : Elles se sont produites 27 fois depuis 1972 (environ tous les 1‑2 ans), mais la fréquence a diminué récemment.

Q : Les secondes intercalaires vont‑elles disparaître ?

R : L’UIT discute d’une suppression d’ici 2035, ce qui arrêterait leur ajout mais ferait dériver l’UTC du temps solaire.

Q : Dois‑je gérer les secondes intercalaires dans mon application ?

R : Pour la plupart des applications, non : utilisez l’UTC standard. Gérez‑les seulement pour les systèmes critiques, scientifiques ou distribués.

Q : Que se passe‑t‑il pendant une seconde intercalaire ?

R : L’UTC ajoute une seconde (23:59:60) pour rester synchronisé avec la rotation terrestre. La plupart des systèmes répètent 23:59:59 ou utilisent le smearing.

Q : Comment tester la gestion des secondes intercalaires ?

R : Testez avec des dates historiques comme 2016-12-31T23:59:60Z et vérifiez que l’application ne plante pas et ne produit pas de résultats incorrects.