JSON Toolkit

Quel format pour les horodatages en JSON

L’essentiel : Les nombres epoch et les chaînes ISO ont chacun leurs compromis, mais c'est les mélanger qui casse réellement les choses. Utilisez ISO 8601 avec un offset, stockez en UTC, affichez dans le fuseau de l'utilisateur.

Débutant~3 min de lecturePublié le 2026-10-30Mis à jour le 2026-10-30
Choisir un format d'horodatage pour les API JSON

L'essentiel : utilisez ISO 8601 avec un offset explicite sur le fil, stockez en UTC avec un Z final, et convertissez seulement à l'affichage ; si vous choisissez plutôt des nombres epoch, fixez globalement secondes contre millisecondes et mettez l'unité dans le nom du champ.

Pourquoi 2026-10-30 14:30:00 ne suffit pas

Cette chaîne ne porte aucun fuseau. 14h30 à Shanghai et 14h30 à Londres sont à huit heures d'écart, et il n'y a aucun moyen de savoir laquelle est visée. new Date('2026-10-30 14:30:00') parse dans le fuseau local du runtime, donc le serveur et le navigateur dérivent deux instants différents d'une seule charge utile — le genre de bug qui ne se reproduit jamais.

Une date nue 2026-10-30 n'est pas un instant du tout. Bien pour les anniversaires et périodes de facturation, faux pour une heure de création.

Deux formats viables

Chaînes ISO 8601

{
  "createdAt": "2026-10-30T14:30:00+08:00",
  "updatedAt": "2026-10-30T06:30:00Z"
}

Lisible, triable quand le format est cohérent, précision à la milliseconde si nécessaire, et auto-descriptif.

Nombres epoch

{ "createdAt": 1793519400 }

Compact et sans ambiguïté, mais illisible, et secondes contre millisecondes est un danger permanent. Si vous choisissez les epochs, standardisez l'unité et mettez-la dans le nom du champ : createdAtMs est bien plus sûr que createdAt.

Conventions à fixer tôt

Élément Convention
Format sur le fil ISO 8601 avec Z ou +08:00
Fuseau de stockage UTC, pour que l'heure d'été n'entre jamais en jeu
Précision La milliseconde suffit
Nommage des champs createdAt, updatedAt, expiresAt
Dates pures Un champ date séparé, par ex. birthday: "1990-01-01"
Durées Entier plus une unité, par ex. timeoutMs: 3000

Affichage

new Intl.DateTimeFormat('en-GB', {
  dateStyle: 'medium',
  timeStyle: 'short',
  timeZone: 'Europe/London',
}).format(new Date('2026-10-30T06:30:00Z'));

Spécifiez timeZone explicitement quand l'affichage ne doit pas suivre l'appareil. Se fier au défaut du navigateur est correct pour les heures destinées à l'utilisateur et faux pour les rapports.

Trois bugs récurrents

Les dates nues se parsent comme minuit UTC. Selon la spécification ECMAScript, les chaînes date-seule sont UTC tandis que les chaînes date-heure sont locales. Cette incohérence est une source fiable de bugs de décalage d'un jour.

Le fuseau de la base ne concorde pas avec le sérialiseur. Le datetime de MySQL n'a pas de fuseau ; écrivez local, lisez en UTC, et tout se décale de l'offset.

L'heure d'été. Stocker des heures locales futures crée des instants qui n'existent pas ou se produisent deux fois. UTC n'a pas de tels trous.

FAQ

Comment choisir entre ISO 8601 et les nombres epoch ?

Utilisez ISO 8601 quand des gens lisent la charge utile, quand vous voulez un ordre de tri lexical, ou quand la valeur doit porter son propre fuseau ; le coût est environ une douzaine d'octets supplémentaires et une bibliothèque de parsing. Utilisez les nombres epoch quand la compacité et un traitement inter-langages trivial comptent plus, mais fixez globalement secondes contre millisecondes et dites quelle unité le champ contient.

Une date nue et un horodatage doivent-ils partager le même champ ?

Non. Une date nue 2026-10-30 est un jour calendaire sans heure ni fuseau, tandis qu'un champ d'horodatage est censé porter un instant exact. Gardez les anniversaires et périodes de facturation dans un champ date séparé, et utilisez un champ ISO 8601 At pour les heures de création ou de mise à jour.

Lectures complémentaires