Que contient réellement une colonne timestamp PostgreSQL ?
Guide pratique sur le stockage timestamp vs timestamptz dans PostgreSQL, les pièges des fuseaux horaires et comment choisir le bon type.
Que contient réellement une colonne timestamp de PostgreSQL ?
PostgreSQL stocke à la fois timestamp et timestamptz sous forme d’un entier 64 bits représentant le nombre de microsecondes depuis le 1er janvier 1970 à 00:00:00 UTC. La différence réside uniquement dans l’étiquetage lors de l’affichage.
Pourquoi est-ce si trompeur ?
- Deux colonnes peuvent afficher des résultats différents pour le même instant
- Votre application insère
2025-07-29 10:00, mais une autre équipe lit02:00 - Les chaînes ISO du frontend ne correspondent pas aux logs du backend
Deux bocaux de pêches : l’un nu, l’autre étiqueté
| Type SQL | Nom officiel | Valeur stockée | Comportement au SELECT |
|---|---|---|---|
timestamp | timestamp without time zone | compteur de microsecondes brut | Restitué tel quel — Postgres ne devine jamais un fuseau |
timestamptz | timestamp with time zone | même compteur | Postgres applique le TimeZone de session avant envoi |
L’analogie
timestamp= un bocal de pêches sans étiquette d’origine. Vous savez que c’est du fruit, mais pas d’où ça vient.timestamptz= un bocal fièrement tamponné « Made in UTC+8 ». Celui qui l’ouvre peut décider de convertir.
Sous le capot : un simple gros nombre
2000-01-01 00:00:00 UTC → 0
2000-01-01 00:00:01 UTC → 1 000 000
- Unité : microseconde (un millionième de seconde)
- Plage : 4713 av. J.-C. – 294 276 ap. J.-C.
- Le stockage est identique pour les deux types ; seule l’interprétation change
Démo express : 15 secondes chrono
-- Le client pense en heure de Shanghai
SET TimeZone = 'Asia/Shanghai';
CREATE TABLE demo (
created_ts timestamp,
created_tz timestamptz
);
INSERT INTO demo VALUES ('2025-07-29 10:00', '2025-07-29 10:00');
| Requête | Résultat | Explication |
|---|---|---|
SELECT created_ts FROM demo; | 2025-07-29 10:00:00 | Valeur brute, sans calcul TZ |
SELECT created_tz FROM demo; | 2025-07-29 10:00:00+08 | Étiquette appliquée à la sortie |
Après SET TimeZone = 'UTC'; | 2025-07-29 02:00:00+00 | Même instant, autre regard |
Pièges fréquents & remèdes rapides
1. Chaque utilisateur a sa montre
- Cause : chaque client définit son propre
TimeZoneavectimestamptz - Remède : soit tout passer en
timestampavec un fuseau de référence, soit forcerSET TimeZone = 'UTC'à la connexion
2. Conserver l’heure « murale » avec le mauvais type
- Agendas locaux (horaires de magasin, échéances) →
timestamp - Flux internationaux (commandes, logs) → stockez l’UTC en
timestamptz
3. APIs qui dérivent
- Expédiez toujours les
timestamptzen ISO 8601 avec l’offset (Zou+08:00) - Le front formate selon le navigateur de l’utilisateur
Mémo : quel type choisir ?
Calendrier local → timestamp
Besoin mondial → timestamptz (stockez en UTC)
- Rapports financiers, plannings de cours →
timestamp - Logs d’audit, commandes e-commerce →
timestamptz
Vérification rapide avec Go Tools
| Besoin | Outil | Mode d’emploi |
|---|---|---|
| Inspecter la valeur epoch | Convertisseur d’époque | Coller 1690622400, cliquer Convert |
| Comparer deux fuseaux | Convertisseur de fuseau | Saisir 10:00 Asia/Shanghai |
| Nettoyer un JSON rempli de dates | Formateur JSON | Coller la charge, cliquer Embellir |
Tous les utilitaires s’exécutent entièrement dans le navigateur — aucune donnée ne quitte votre machine.
En résumé
- Les deux types temporels de Postgres sont des compteurs de microsecondes ; seule l’étiquette fait la différence
- Se tromper de type mène à des horloges folles et des calculs erronés
- Testez, convertissez et validez avec les bons outils pour gagner des heures de débogage