Outils pour développeurs·6 min

Comprendre les timestamps Unix : un guide pour développeurs

Ce que sont les timestamps Unix, comment ils fonctionnent, secondes intercalaires, le problème de 2038 et conversion pratique.

Pourquoi les développeurs doivent comprendre les timestamps Unix

Un timestamp Unix est un entier représentant le nombre de secondes écoulées depuis 00:00:00 UTC le 1er janvier 1970 (l'époque Unix). C'est la lingua franca du temps en informatique : les bases de données les indexent, les APIs les renvoient, les systèmes de fichiers les stockent, et les protocoles comme NTP et HTTP les utilisent. Tout développeur finit par devoir convertir entre timestamps Unix et dates lisibles par l'humain — et par déboguer les problèmes qui surviennent quand différents systèmes représentent le temps différemment.

Ce guide couvre ce que sont les timestamps Unix, comment ils fonctionnent dans différents langages, les complications de fuseau horaire et de seconde intercalaire, et le problème de 2038 à venir.

Comment fonctionnent les timestamps Unix

Un timestamp Unix est juste un compte entier de secondes. Il n'y a pas de fuseau horaire, pas d'heure d'été, pas d'arithmétique de calendrier. Ajouter 86 400 à un timestamp avance toujours la date d'exactement un jour en UTC.

``` 0 = 1970-01-01 00:00:00 UTC (l'époque) 1,000 = 1970-01-01 00:16:40 UTC 1,000,000 = 1970-01-12 13:46:40 UTC 1,000,000,000 = 2001-09-09 01:46:40 UTC (le « billionième ») 1,500,000,000 = 2017-07-14 02:40:00 UTC 2,000,000,000 = 2033-05-18 03:33:20 UTC 2,147,483,647 = 2038-01-19 03:14:07 UTC (max 32 bits signé) ```

La plus grande valeur représentable dépend du type d'entier :

  • 32 bits signé : 2 147 483 647 (2^31 − 1) → 2038-01-19 03:14:07 UTC
  • 32 bits non signé : 4 294 967 295 (2^32 − 1) → 2106-02-07 06:28:15 UTC
  • 64 bits signé : 9 223 372 036 854 775 807 → année 292 277 026 596

C'est pourquoi le problème de 2038 existe : tout timestamp signé 32 bits déborde le 2038-01-19. Les timestamps 64 bits évitent le problème pour des centaines de milliards d'années.

Temps Unix vs UTC : le problème de la seconde intercalaire

Strictement, le temps Unix ignore les secondes intercalaires. Il compte chaque seconde comme s'il y en avait exactement 86 400 par jour, même quand les autorités internationales du temps ajoutent une seconde intercalaire à l'UTC. Après que 27 secondes intercalaires ont été insérées (à partir de 2024), le temps Unix est maintenant environ 27 secondes en avance sur l'UTC « vrai ».

En pratique, cela a rarement d'importance. TAI (Temps Atomique International) maintient des secondes parfaites, et l'UTC reste à moins de 0,9 seconde de UT1 (temps de rotation de la Terre) en ajoutant des secondes intercalaires. Le temps Unix utilise simplement le compte de secondes de TAI moins un décalage fixe.

Si vous avez besoin de temps atomique strict, utilisez TAI directement. Pour tout le reste, la petite dérive du temps Unix est sans importance.

Fuseaux horaires et décalages

Un timestamp Unix se réfère à un unique instant dans le temps. Pour l'afficher sous une forme lisible par l'humain, vous appliquez un décalage de fuseau horaire. Décalages courants :

| Zone | Abréviation | Décalage depuis UTC | |------|--------------|---------------------| | Temps Universel Coordonné | UTC | 0 | | Est des États-Unis (hiver) | EST | −5 | | Est des États-Unis (été) | EDT | −4 | | Pacifique des États-Unis (hiver) | PST | −8 | | Pacifique des États-Unis (été) | PDT | −7 | | Royaume-Uni (hiver) | GMT | 0 | | Royaume-Uni (été) | BST | +1 | | Europe Centrale (hiver) | CET | +1 | | Europe Centrale (été) | CEST | +2 | | Japon | JST | +9 | | Chine | CST | +8 | | Inde | IST | +5:30 | | Australie (Sydney, hiver) | AEST | +10 | | Australie (Sydney, été) | AEDT | +11 |

Notez que l'Inde et la Chine utilisent un décalage unique toute l'année (pas d'heure d'été). Les États-Unis, le Royaume-Uni et la majeure partie de l'Europe observent l'heure d'été, ce qui complique tout.

Un bug courant : un serveur stocke un timestamp Unix (toujours UTC), puis l'affiche sans appliquer le décalage local de l'utilisateur, et l'utilisateur voit une heure décalée de plusieurs heures. Stockez toujours en UTC, convertissez toujours en local au moment de l'affichage.

Le problème de 2038 en détail

Le problème de 2038 (aussi appelé Y2K38) est le débordement d'entier signé 32 bits qui se produira le 2038-01-19 03:14:07 UTC. La seconde suivante déborde à −2 147 483 648, ce qui sur la plupart des systèmes est interprété comme 1901-12-13 20:45:52 UTC. Tout ce qui dépend des timestamps Unix comme entiers signés 32 bits se cassera :

  • Systèmes de fichiers qui stockent le mtime en time_t 32 bits
  • Bases de données anciennes (MySQL ancien, certaines builds de SQLite)
  • Systèmes embarqués (routeurs, appareils IoT, voitures)
  • Protocoles réseau qui utilisent des champs de temps 32 bits (NTP, DNS, Kerberos, certains handshakes TLS)

Les systèmes modernes (Linux 64 bits, macOS 64 bits, Windows moderne, bases de données modernes) ont déjà migré vers 64 bits. Le risque se trouve dans le code hérité et embarqué qui n'a pas été mis à jour.

La correction : changez le type de données de `time_t` (32 bits) à `int64_t` (ou équivalent). Un changement de déclaration, plus une recompilation. Le défi est de trouver chaque endroit où vit l'hypothèse 32 bits — formats de fichier, protocoles réseau, données persistées, bibliothèques tierces.

Travailler avec les timestamps Unix en code

Python

Le module `datetime` de Python est l'outil canonique.

```python import datetime from zoneinfo import ZoneInfo

# Timestamp Unix actuel (secondes, float) import time now = time.time() # 1700000000.123

# Convertir timestamp Unix en datetime (UTC) ts = 1700000000 utc = datetime.datetime.fromtimestamp(ts, tz=datetime.timezone.utc) # 2023-11-14 22:13:20+00:00

# Convertir timestamp Unix en datetime (zone spécifique) ny = datetime.datetime.fromtimestamp(ts, tz=ZoneInfo("America/New_York")) # 2023-11-14 17:13:20-05:00

# Convertir datetime en timestamp Unix d = datetime.datetime(2023, 11, 14, 22, 13, 20, tzinfo=datetime.timezone.utc) ts = int(d.timestamp()) # 1700000000

# Formater en ISO 8601 print(utc.isoformat()) # 2023-11-14T22:13:20+00:00 ```

Attention : `datetime.fromtimestamp(ts)` (sans `tz`) utilise le fuseau horaire local, ce qui est rarement ce que vous voulez dans un contexte serveur. Passez toujours un fuseau horaire explicite.

JavaScript

JavaScript utilise les millisecondes, pas les secondes. `Date.now()` retourne les millisecondes depuis l'époque.

```js // Timestamp Unix actuel en millisecondes const now = Date.now(); // p. ex., 1700000000000

// Timestamp Unix actuel en secondes const nowSec = Math.floor(Date.now() / 1000);

// Convertir des secondes en millisecondes et créer un Date const date = new Date(1700000000 * 1000); // 2023-11-14T22:13:20.000Z

// Convertir des millisecondes en secondes const ts = Math.floor(date.getTime() / 1000);

// Afficher dans un fuseau horaire spécifique avec Intl console.log(date.toLocaleString("en-US", { timeZone: "Asia/Tokyo" })); // 11/15/2023, 7:13:20 AM

// ISO 8601 console.log(date.toISOString()); // 2023-11-14T22:13:20.000Z ```

Le plus grand piège de JavaScript : tous les autres langages utilisent les secondes ; JavaScript utilise les millisecondes. Oublier de multiplier ou diviser par 1 000 est la source d'innombrables bugs « décalés d'un facteur 1 000 ».

SQL

La plupart des bases de données supportent les timestamps Unix nativement ou via des fonctions.

```sql -- MySQL SELECT UNIX_TIMESTAMP(NOW()); -- timestamp actuel (secondes) SELECT FROM_UNIXTIME(1700000000); -- 2023-11-14 22:13:20 SELECT FROM_UNIXTIME(1700000000, '%Y-%m-%d %H:%i:%s');

-- PostgreSQL SELECT EXTRACT(EPOCH FROM NOW()); -- timestamp actuel (secondes, float) SELECT TO_TIMESTAMP(1700000000); -- 2023-11-14 22:13:20+00

-- SQLite SELECT strftime('%Y-%m-%dT%H:%M:%fZ', 'unixepoch', 1700000000); -- 2023-11-14T22:13:20.000Z ```

`UNIX_TIMESTAMP()` de MySQL retourne des secondes ; `EXTRACT(EPOCH FROM ...)` de PostgreSQL retourne des secondes avec précision fractionnelle. SQLite nécessite la recette manuelle avec `strftime`.

Bash

La commande `date` gère les timestamps Unix sur tout système Unix.

```bash # Timestamp Unix actuel date +%s # 1700000000

# Convertir un timestamp Unix en chaîne de date # Linux (GNU date) date -d @1700000000 # Tue Nov 14 22:13:20 PM UTC 2023

# macOS (BSD date) date -r 1700000000 # Tue Nov 14 22:13:20 UTC 2023

# Convertir une chaîne de date en timestamp Unix # Linux date -d "2023-11-14 22:13:20 UTC" +%s # macOS date -j -f "%Y-%m-%d %H:%M:%S" "2023-11-14 22:13:20" +%s

# Afficher dans un fuseau horaire spécifique TZ="Asia/Tokyo" date -d @1700000000 # Wed Nov 15 07:13:20 JST 2023 ```

Pour une référence rapide : `date +%s` pour « maintenant en temps Unix » est un one-liner que vous utiliserez chaque semaine.

Stocker les timestamps dans les bases de données

Meilleures pratiques pour le stockage en base de données :

  1. Stockez comme entiers (BIGINT) : Les timestamps Unix natifs sont peu coûteux à stocker, faciles à indexer, simples à comparer.
  2. Utilisez toujours UTC : Convertissez en fuseau local seulement au moment de l'affichage.
  3. Utilisez BIGINT, pas INT : Un entier signé 32 bits déborde en 2038. Utilisez toujours 64 bits.
  4. Considérez la précision en millisecondes : Pour le logging d'événements haute fréquence (trading, gaming, télémétrie), 1 seconde de résolution est trop grossier. Stockez comme BIGINT millisecondes.
  5. Utilisez TIMESTAMP WITH TIME ZONE : Le `timestamptz` de PostgreSQL est le plus robuste. Le `TIMESTAMP` de MySQL a le problème de 2038 ; utilisez `DATETIME` à la place.
  6. Indexez les colonnes timestamp : Les requêtes comme `WHERE created_at > ?` sont extrêmement courantes. Un index BTREE sur une colonne timestamp les rend rapides.

Un schéma courant :

```sql CREATE TABLE events ( id BIGSERIAL PRIMARY KEY, event_type TEXT NOT NULL, payload JSONB NOT NULL, created_at BIGINT NOT NULL, -- Unix ms INDEX idx_events_created (created_at) ); ```

Pièges courants

Le bug de millisecondes de JavaScript

Les timestamps JavaScript sont en millisecondes ; tous les autres grands langages utilisent les secondes. Les mélanger produit des timestamps décalés d'un facteur 1 000.

```js // Depuis un backend Python const python_ts = 1700000000; // secondes const js_date = new Date(python_ts); // 1970-01-20T08:13:20.000Z ← FAUX !

// Correct : multiplier par 1 000 const js_date = new Date(python_ts * 1000); ```

Bugs d'affichage de fuseau horaire

Un timestamp se réfère à un instant dans le temps, pas à une date. Si votre serveur journalise « 2023-11-14 22:13:20 » sans indiquer UTC ou local, l'utilisateur n'a aucun moyen de savoir lequel c'est. Toujours :

  • Stockez comme timestamp Unix (intrinsèquement UTC)
  • Envoyez aux clients avec un fuseau horaire explicite
  • Convertissez en local au moment de l'affichage en utilisant le fuseau réel de l'utilisateur

```js // Le serveur envoie "2023-11-14T22:13:20Z" (Z = UTC) // Le client rend dans le fuseau local de l'utilisateur const d = new Date("2023-11-14T22:13:20Z"); console.log(d.toLocaleString()); // "11/14/2023, 5:13:20 PM" (en EST) ```

Cas limites de l'heure d'été

Un jour de 24 heures au printemps fait en fait 23 heures (l'heure d'été saute une heure) ; un jour de 24 heures en automne fait 25 heures. Le code qui suppose « ajouter 86 400 pour obtenir demain » fonctionne bien ; le code qui fait « ajouter 24 × 60 × 60 » ou « demain à 2:30 AM » peut échouer aux transitions d'heure d'été.

```python # Ceci est un jour de 23 ou 25 heures dans les fuseaux avec DST d = datetime.datetime(2024, 3, 10, 1, 0, 0, tzinfo=ZoneInfo("America/New_York")) # DST commence print((d + datetime.timedelta(days=1)).isoformat()) # 2024-03-11T01:00:00-05:00 ← correct print((d + datetime.timedelta(hours=24)).isoformat()) # 2024-03-11T02:00:00-04:00 ← DST a sauté, ceci est 25 heures plus tard ```

Pour la planification et les calculs d'heure de la journée, préférez des bibliothèques (Luxon, Arrow, date-fns) qui gèrent correctement ces cas limites.

Méthode 1 : Utilisez le convertisseur de timestamp de UtilBoxx (Recommandé)

Pour des conversions rapides pendant le développement, le Convertisseur de Timestamp de UtilBoxx est un outil privé, dans le navigateur, qui convertit entre les timestamps Unix et les dates dans n'importe quel fuseau horaire, supporte à la fois les secondes et les millisecondes, et s'exécute entièrement côté client. Pas de téléversement, pas d'inscription, pas de logs. Ajoutez-le aux favoris pour la prochaine fois où vous aurez besoin de décoder un timestamp inconnu d'une réponse API.

Conclusion

Les timestamps Unix sont simples, rapides et universels — mais l'écosystème qui les entoure (fuseaux horaires, secondes intercalaires, le problème de 2038, confusion millisecondes vs secondes) est plein de pièges. Tout développeur finit par tomber sur chacun d'eux ; la seule défense est de savoir qu'ils existent.

Meilleures pratiques :

  • Stockez comme entiers 64 bits en UTC
  • Convertissez en local au moment de l'affichage avec le fuseau horaire réel de l'utilisateur
  • Utilisez une vraie bibliothèque de fuseaux horaires (Luxon, date-fns-tz, zoneinfo) pour les calculs de temps non triviaux
  • Auditez les timestamps 32 bits maintenant si vous maintenez du code hérité

Les timestamps Unix sont l'un des plus anciens formats de données encore utilisés, et ils nous survivront à tous — mais seulement si nous les utilisons correctement.