RFC 3339 - Date and Time on the Internet: Timestamps
- Statut: Proposed Standard
- Publié: July 2002
- Stream: IETF
- Errata: Pas d'errata
Status of this Memo (Statut de ce mémorandum)
Ce document spécifie un protocole de suivi de normes Internet pour la communauté Internet et demande des discussions et des suggestions d'amélioration. Pour le statut de normalisation de ce protocole, reportez-vous à la version actuelle des "Internet Official Protocol Standards" (STD 1). La distribution de ce mémorandum n'est pas limitée.
Copyright Notice (Avis de droits d'auteur)
Copyright (C) The Internet Society (2002). All Rights Reserved.
Abstract (Résumé)
Ce document définit un format de date et d'heure destiné aux protocoles Internet, qui constitue un profil (Profile) de la norme ISO 8601 pour la représentation des dates et heures en utilisant le calendrier grégorien (Gregorian Calendar).
目录 (Table des matières)
- 1. Introduction
- 2. Definitions (Définitions)
- 3. Two Digit Years (Années à deux chiffres)
- 4. Local Time (Heure locale)
- 4.1 Coordinated Universal Time (UTC)
- 4.2 Local Offsets
- 4.3 Unknown Local Offset Convention
- 4.4 Unqualified Local Time
- 5. Date and Time format (Format de date et d'heure)
- 5.1 Ordering
- 5.2 Human Readability
- 5.3 Rarely Used Options
- 5.4 Redundant Information
- 5.5 Simplicity
- 5.6 Internet Date/Time Format
- 5.7 Restrictions
- 5.8 Examples
- 6. References (Références)
- 7. Security Considerations (Considérations de sécurité)
附录 (Annexes)
- Appendix A. ISO 8601 Collected ABNF
- Appendix B. Day of the Week
- Appendix C. Leap Years
- Appendix D. Leap Seconds
相关资源 (Ressources connexes)
- Texte original officiel: RFC 3339 (TXT)
- Page officielle: RFC 3339 DataTracker
- Errata: RFC Editor Errata
快速参考 (Référence rapide)
Format standard
YYYY-MM-DDTHH:MM:SS.sssZ
YYYY-MM-DDTHH:MM:SS.sss±HH:MM
Exemples
1985-04-12T23:20:50.52Z
1996-12-19T16:39:57-08:00
1990-12-31T23:59:60Z (seconde intercalaire)
1937-01-01T12:00:27.87+00:20
Note importante: Il s'agit du format standard pour représenter les horodatages dans les protocoles Internet, largement utilisé dans les protocoles et formats de données tels que HTTP, JSON, XML, etc.
1. Introduction
Les formats de date et d'heure causent beaucoup de confusion et de problèmes d'interopérabilité sur Internet. Ce document aborde de nombreux problèmes rencontrés et formule des recommandations pour améliorer la cohérence et l'interopérabilité lors de la représentation et de l'utilisation des dates et heures dans les protocoles Internet.
Ce document comprend un profil Internet de la norme ISO 8601 [ISO8601] pour la représentation des dates et heures utilisant le calendrier grégorien (Gregorian Calendar).
Il existe de nombreuses façons dont les valeurs de date et d'heure peuvent apparaître dans les protocoles Internet : ce document se concentre sur une seule utilisation courante, à savoir les horodatages (Timestamps) pour les événements de protocoles Internet. Cette considération limitée a les conséquences suivantes :
Limitations et hypothèses pour les horodatages
o Ère actuelle
Toutes les dates et heures sont supposées être dans l'« ère actuelle », quelque part entre 0000 après J.-C. et 9999 après J.-C.
o Relation avec UTC
Toutes les heures exprimées ont une relation déclarée (décalage) avec le temps universel coordonné (Coordinated Universal Time, UTC). (Cela est distinct de certaines utilisations dans les applications de planification où une heure locale et un emplacement peuvent être connus, mais la relation réelle avec UTC peut dépendre des actions inconnues ou inconnaissables des politiciens ou des administrateurs. L'heure UTC correspondant à 17h00 le 23 mars 2005 à New York peut dépendre de décisions administratives concernant l'heure d'été. Cette spécification évite délibérément de telles considérations.)
o Horodatages historiques
Les horodatages peuvent représenter des moments survenus avant l'introduction de l'UTC. Ces horodatages sont relatifs au temps universel (Universal Time), en utilisant les meilleures pratiques disponibles au moment indiqué.
o Représentation des points dans le temps
Les expressions de date et d'heure représentent un instant dans le temps (Instant in Time). Les descriptions de périodes de temps (Time Periods) ou d'intervalles (Intervals) ne sont pas couvertes ici.
Points clés :
- Cette spécification se concentre sur les horodatages, et non sur les périodes ou la planification
- Toutes les heures doivent avoir une relation définie avec UTC
- Prend en charge la plage de dates de 0000 après J.-C. à 9999 après J.-C.
- Évite la dépendance aux décisions politiques concernant les fuseaux horaires locaux (telles que les ajustements de l'heure d'été)
2. Définitions
Les mots-clés « MUST », « MUST NOT », « REQUIRED », « SHALL », « SHALL NOT », « SHOULD », « SHOULD NOT », « RECOMMENDED », « MAY » et « OPTIONAL » dans ce document doivent être interprétés comme décrit dans la RFC 2119 [RFC2119].
Définitions des termes
UTC (Coordinated Universal Time, Temps Universel Coordonné)
Temps Universel Coordonné tel que maintenu par le Bureau International des Poids et Mesures (BIPM).
second (seconde)
Unité de base de mesure du temps dans le Système International d'Unités. Elle est définie comme la durée de 9 192 631 770 cycles de la lumière micro-onde absorbée ou émise par la transition hyperfine des atomes de césium-133 (cesium-133) dans leur état fondamental non perturbé par des champs externes.
minute
Une période de temps de 60 secondes. Cependant, voir également la section 5.7 et l'annexe D pour savoir comment les secondes intercalaires (Leap Seconds) sont dénotées dans les minutes.
hour (heure)
Une période de temps de 60 minutes.
day (jour)
Une période de temps de 24 heures.
leap year (année bissextile)
Dans le calendrier grégorien, une année qui a 366 jours. Une année bissextile est une année dont le nombre est divisible par 4, mais pas par 100, sauf si elle est également divisible par 400.
Règles des années bissextiles :
if (année % 400 == 0) → année bissextile
else if (année % 100 == 0) → année commune
else if (année % 4 == 0) → année bissextile
else → année commune
Exemples :
- 2000 : année bissextile (divisible par 400)
- 1900 : année commune (divisible par 100 mais pas par 400)
- 2004 : année bissextile (divisible par 4)
- 2001 : année commune
ABNF (Augmented Backus-Naur Form, Forme de Backus-Naur Augmentée)
Un format pour représenter les chaînes permises dans un protocole ou un langage, tel que défini dans [ABNF].
Email Date/Time Format (Format de date/heure des e-mails)
Le format de date/heure utilisé par le courrier Internet tel que défini par la RFC 2822 [IMAIL-UPDATE].
Internet Date/Time Format (Format de date/heure Internet)
Le format de date défini dans la section 5 de ce document.
Timestamp (Horodatage)
Ce terme est utilisé dans ce document pour faire référence à une représentation non ambiguë (Unambiguous Representation) d'un instant dans le temps.
Z
Un suffixe qui, lorsqu'il est appliqué à une heure, désigne un décalage UTC de 00:00 ; souvent prononcé « Zulu » d'après la représentation de l'alphabet phonétique de l'OACI de la lettre « Z ».
Exemple :
2002-07-15T10:30:00Z
Représente : 15 juillet 2002 à 10:30:00 UTC
Informations complémentaires
Pour plus d'informations concernant les échelles de temps, voir :
- L'annexe E de [NTP]
- La section 3 de [ISO8601]
- Les documents appropriés de l'UIT [ITU-R-TF]
Note : La compréhension de ces termes fondamentaux est essentielle pour mettre en œuvre et utiliser correctement cette spécification, en particulier les définitions des années bissextiles et des secondes intercalaires.
3. Années à deux chiffres
Les exigences suivantes traitent des problèmes d'ambiguïté causés par les années à deux chiffres :
Exigences
o Les années à quatre chiffres sont obligatoires
Les protocoles Internet doivent (MUST) générer des années à quatre chiffres dans les dates.
Exemples corrects :
✅ 2002-07-15
✅ 1999-12-31
Exemples incorrects :
❌ 02-07-15
❌ 99-12-31
o Les années à deux chiffres sont dépréciées
L'utilisation d'années à deux chiffres est dépréciée (Deprecated). Si une année à deux chiffres est reçue, elle ne devrait (SHOULD) être acceptée que si une mauvaise interprétation ne causera pas d'échec de protocole ou de traitement (par exemple, si elle est utilisée uniquement à des fins de journalisation ou de traçage).
o Gestion des années à trois chiffres
Les programmes qui utilisent des années à deux chiffres peuvent représenter les années après 1999 sous forme de trois chiffres. Cela se produira si le programme soustrait simplement 1900 de l'année sans vérifier le nombre de chiffres. Les programmes qui souhaitent gérer de manière robuste les dates générées par de tels logiciels défectueux peuvent (MAY) ajouter 1900 aux années à trois chiffres.
Exemple :
Sortie du programme défectueux : 102 (représentant l'année 2002)
Analyse robuste : 102 + 1900 = 2002
o Gestion des chiffres de décennie non numériques
Les programmes qui utilisent des années à deux chiffres peuvent représenter les années après 1999 comme ":0", ":1", ... ":9", ";0", .... Cela se produira si le programme soustrait simplement 1900 de l'année et ajoute le chiffre de la décennie au caractère zéro US-ASCII. Les programmes qui souhaitent gérer de manière robuste les dates générées par de tels logiciels défectueux devraient (SHOULD) détecter les chiffres de décennie non numériques et les interpréter de manière appropriée.
Exemple :
Sortie du programme défectueux :
- '0' + 10 = ':' (représentant les années 2000, code ASCII 58)
- '0' + 11 = ';' (représentant les années 2010, code ASCII 59)
L'analyse robuste doit reconnaître ces modèles et les convertir correctement
Leçons du bogue de l'an 2000
Les problèmes liés aux années à deux chiffres démontrent amplement pourquoi toutes les dates et heures utilisées dans les protocoles Internet doivent (MUST) être entièrement qualifiées (Fully Qualified).
Recommandations d'implémentation
Lors de la génération de dates
✅ Toujours utiliser des années à quatre chiffres : 2024-12-21
❌ Ne jamais utiliser deux chiffres : 24-12-21
Lors de l'analyse de dates
# Exemple d'analyse robuste
def parse_year(year_str):
if len(year_str) == 4:
return int(year_str) # Quatre chiffres corrects
elif len(year_str) == 2:
# Déprécié, pour compatibilité ascendante uniquement
year = int(year_str)
if year < 70:
return 2000 + year
else:
return 1900 + year
elif len(year_str) == 3:
# Gérer les logiciels défectueux
return 1900 + int(year_str)
else:
raise ValueError("Format d'année invalide")
Avertissement : Bien que cette section décrive comment gérer les années à deux chiffres, cela est uniquement pour la compatibilité ascendante. Les nouvelles implémentations ne doivent absolument pas (MUST NOT) générer d'années à deux chiffres.
4. Heure locale
4.1. Temps Universel Coordonné (UTC)
Étant donné que les règles d'heure d'été pour les fuseaux horaires locaux sont si complexes et peuvent changer en fonction de la législation locale à des moments imprévisibles, la véritable interopérabilité est mieux réalisée en utilisant le Temps Universel Coordonné (UTC). Cette spécification ne prend pas en compte les règles de fuseau horaire local.
Pourquoi utiliser l'UTC ?
- ✅ Norme temporelle unifiée mondialement
- ✅ Non affecté par l'heure d'été
- ✅ Non affecté par les décisions politiques
- ✅ Garantit l'interopérabilité
4.2. Décalages locaux
Le décalage entre l'heure locale et l'UTC est souvent une information utile. Par exemple, dans le courrier électronique (RFC2822, [IMAIL-UPDATE]), le décalage local fournit une heuristique utile pour déterminer la probabilité d'une réponse rapide. Les tentatives d'étiquetage des décalages locaux avec des chaînes alphabétiques ont entraîné une mauvaise interopérabilité dans le passé [IMAIL], [HOST-REQ]. En conséquence, RFC2822 [IMAIL-UPDATE] a rendu les décalages numériques obligatoires.
Calcul du décalage numérique
Les décalages numériques sont calculés comme « heure locale moins UTC ». L'heure équivalente en UTC peut donc être déterminée en soustrayant le décalage de l'heure locale.
Exemple 1 :
Heure locale : 18:50:00-04:00
Heure UTC : 18:50:00 - (-04:00) = 18:50:00 + 04:00 = 22:50:00Z
Vérification : Eastern Daylight Time (EDT) est UTC-4
Exemple 2 :
Heure locale : 15:30:00+08:00
Heure UTC : 15:30:00 - (+08:00) = 15:30:00 - 08:00 = 07:30:00Z
Vérification : China Standard Time (CST) est UTC+8
Notes importantes
Note : Conformément à ISO 8601, les décalages numériques ne représentent que les fuseaux horaires qui diffèrent de l'UTC par un nombre entier de minutes. Cependant, de nombreux fuseaux horaires historiques diffèrent de l'UTC par un nombre non entier de minutes. Pour représenter exactement de tels horodatages historiques, les applications doivent (MUST) les convertir dans un fuseau horaire représentable.
Exemples de fuseaux horaires historiques :
Certaines heures locales à la fin du 19e siècle :
- Amsterdam : UTC+00:19:32
- Paris : UTC+00:09:21
Ceux-ci ne peuvent pas être représentés précisément dans RFC 3339 et doivent être arrondis à la minute la plus proche
4.3. Convention de décalage local inconnu
Si l'heure en UTC est connue, mais que le décalage par rapport à l'heure locale est inconnu, cela peut être représenté avec un décalage de "-00:00". Cela diffère sémantiquement d'un décalage de "Z" ou "+00:00", qui implique que l'UTC est le point de référence préféré pour l'heure spécifiée. RFC2822 [IMAIL-UPDATE] décrit une convention similaire pour le courrier électronique.
Distinction des trois représentations
Z ou +00:00 :
2002-07-15T10:30:00Z
2002-07-15T10:30:00+00:00
Signification : Cette heure EST l'heure UTC, l'UTC est le point de référence préféré
-00:00 :
2002-07-15T10:30:00-00:00
Signification : L'heure UTC est 10:30:00, mais le décalage du fuseau horaire local est inconnu
(possiblement d'un système qui ne connaît pas son réglage de fuseau horaire)
Scénarios d'utilisation :
Scénario 1 : Journaux serveur, connus pour être en UTC → utiliser Z
Scénario 2 : Horodatage généré par un appareil, l'appareil est en UTC mais ne connaît pas le fuseau local → utiliser -00:00
Scénario 3 : Explicitement à Londres (GMT) → utiliser +00:00
4.4. Heure locale non qualifiée
Un certain nombre d'appareils actuellement connectés à Internet font fonctionner leurs horloges internes en heure locale et ne connaissent pas l'UTC. Bien qu'Internet ait une tradition d'accepter la réalité lors de la conception des spécifications, cela ne devrait pas se faire au détriment de l'interopérabilité. Étant donné que l'interprétation d'un fuseau horaire local non qualifié échouera dans environ 23/24 du globe,
Exigences obligatoires
Les protocoles Internet doivent (MUST) générer des horodatages entièrement qualifiés.
Cela signifie que les protocoles Internet ne doivent pas (MUST NOT) utiliser l'heure locale sans informations de fuseau horaire.
Exemples incorrects :
❌ 2002-07-15T10:30:00 (aucune information de fuseau horaire)
Exemples corrects :
✅ 2002-07-15T10:30:00Z (UTC)
✅ 2002-07-15T10:30:00+08:00 (fuseau horaire explicite)
✅ 2002-07-15T10:30:00-00:00 (UTC mais zone inconnue)
Problèmes d'interopérabilité
Si une heure locale non qualifiée est utilisée :
Expéditeur : 2002-07-15T10:30:00 (heure locale de New York, en fait UTC-4)
Destinataire à Tokyo : Interprète comme heure de Tokyo (UTC+9)
Erreur de différence horaire : 13 heures !
Recommandations d'implémentation
Conception du système
# Recommandé : Toujours stocker l'heure en UTC
def store_timestamp():
utc_time = datetime.now(timezone.utc)
return utc_time.isoformat() # 2024-12-21T10:30:00+00:00
# Lors de l'affichage : Convertir dans le fuseau horaire local de l'utilisateur
def display_timestamp(utc_time, user_timezone):
local_time = utc_time.astimezone(user_timezone)
return local_time.isoformat()
Stockage en base de données
-- Recommandé : Utiliser TIMESTAMP WITH TIME ZONE
CREATE TABLE events (
id SERIAL,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Éviter : TIMESTAMP WITHOUT TIME ZONE (cause de l'ambiguïté)
Principe clé : Stocker en interne en UTC, convertir dans le fuseau horaire local lors de l'affichage. Ne jamais utiliser d'horodatages sans informations de fuseau horaire pour l'échange de données.
5. Format de date et d'heure
Cette section discute des qualités souhaitables des formats de date et d'heure et définit un profil d'ISO 8601 pour une utilisation sur Internet.
5.1. Ordering (Ordonnancement)
Si les composants de date et d'heure sont ordonnés du moins précis au plus précis, une propriété utile est obtenue. En supposant que les fuseaux horaires des dates et heures sont identiques (par exemple, tous en UTC), exprimés en utilisant la même chaîne (par exemple, tous "Z" ou tous "+00:00"), et que toutes les heures ont le même nombre de chiffres de secondes fractionnaires, alors les chaînes de date et d'heure peuvent être triées comme des chaînes (par exemple, en utilisant la fonction strcmp() en C) et produiront une séquence ordonnée temporellement. La présence de ponctuation optionnelle violerait cette caractéristique.
Exemple :
Ordre correct (année-mois-jour heure:minute:seconde) :
2002-01-15T10:00:00Z
2002-07-20T15:30:00Z
2002-12-31T23:59:59Z
Format incorrect (mois/jour/année) ne peut pas être trié correctement :
01/15/2002 10:00:00
12/31/2002 23:59:59 ← Le tri de chaîne place ceci avant juillet
07/20/2002 15:30:00
5.2. Human Readability (Lisibilité humaine)
La lisibilité humaine s'est révélée être une caractéristique précieuse des protocoles Internet. Les protocoles lisibles par l'homme réduisent considérablement les coûts de débogage car telnet suffit souvent comme client de test et les analyseurs de réseau n'ont pas besoin d'être modifiés avec la connaissance du protocole. D'autre part, la lisibilité humaine entraîne parfois des problèmes d'interopérabilité.
Exemples de problèmes :
❌ "10/11/1996" est complètement inadapté pour l'échange mondial
États-Unis : 11 octobre 1996
Europe : 10 novembre 1996
❌ Traduction des abréviations de mois
Anglais : "Jan", "Feb", "Mar"
Français : "Jan", "Fév", "Mar" ← Rompt l'interopérabilité
Parce qu'aucun format de date et d'heure n'est lisible selon les conventions de tous les pays, les clients Internet devraient (SHOULD) être prêts à transformer les dates dans un format d'affichage adapté à la localité. Cela peut inclure la traduction de l'UTC en heure locale.
5.3. Rarely Used Options (Options rarement utilisées)
Un format qui inclut des options rarement utilisées est susceptible de causer des problèmes d'interopérabilité. C'est parce que les options rarement utilisées sont moins susceptibles d'être utilisées dans les tests alpha ou bêta, donc les bogues d'analyse sont moins susceptibles d'être découverts. Les options rarement utilisées devraient être rendues obligatoires ou omises dans la mesure du possible pour des raisons d'interopérabilité.
Le format défini ci-dessous n'inclut qu'une seule option rarement utilisée : Fractions de seconde (Fractions of a Second). Il est prévu que cela ne sera utilisé que par des applications qui nécessitent un ordonnancement strict des horodatages de date/heure ou qui ont des exigences de précision inhabituelles.
5.4. Redundant Information (Information redondante)
Si un format de date/heure inclut des informations redondantes, il introduit la possibilité que les informations redondantes ne soient pas corrélées. Par exemple, inclure le jour de la semaine dans un format de date/heure introduit la possibilité que le jour de la semaine soit incorrect mais que la date soit correcte, ou vice versa. Puisqu'il n'est pas difficile de calculer le jour de la semaine à partir de la date (voir Annexe B), le jour de la semaine ne devrait pas être inclus dans un format de date/heure.
Exemple de problème :
❌ "Monday, 2002-07-16T10:00:00Z"
Problème : Le 16 juillet 2002 est en fait un mardi, pas un lundi
Si le jour et la date ne correspondent pas, lequel faut-il faire confiance ?
✅ "2002-07-16T10:00:00Z"
Solution : Omettre le jour de la semaine, calculer si nécessaire
5.5. Simplicity (Simplicité)
L'ensemble complet des formats de date et d'heure spécifiés dans ISO 8601 [ISO8601] est assez complexe dans une tentative de fournir plusieurs représentations et représentations partielles. L'Annexe A contient une tentative de traduire la syntaxe complète d'ISO 8601 en ABNF. Les protocoles Internet ont des exigences quelque peu différentes et la simplicité s'est révélée être une caractéristique importante. De plus, les protocoles Internet ont généralement besoin d'une spécification complète des données pour atteindre une véritable interopérabilité. Par conséquent, la syntaxe complète d'ISO 8601 est jugée trop complexe pour la plupart des protocoles Internet.
La section suivante définit un profil d'ISO 8601 pour une utilisation sur Internet. C'est un sous-ensemble cohérent du format étendu ISO 8601. La simplicité est obtenue en rendant la plupart des champs et de la ponctuation obligatoires.
5.6. Internet Date/Time Format (Format de date/heure Internet)
Le profil suivant des dates ISO 8601 [ISO8601] devrait (SHOULD) être utilisé dans les nouveaux protocoles sur Internet. Ceci est spécifié en utilisant la notation de description de syntaxe définie dans [ABNF].
Définition de la syntaxe ABNF
date-fullyear = 4DIGIT
date-month = 2DIGIT ; 01-12
date-mday = 2DIGIT ; 01-28, 01-29, 01-30, 01-31 based on
; month/year
time-hour = 2DIGIT ; 00-23
time-minute = 2DIGIT ; 00-59
time-second = 2DIGIT ; 00-58, 00-59, 00-60 based on leap second
; rules
time-secfrac = "." 1*DIGIT
time-numoffset = ("+" / "-") time-hour ":" time-minute
time-offset = "Z" / time-numoffset
partial-time = time-hour ":" time-minute ":" time-second
[time-secfrac]
full-date = date-fullyear "-" date-month "-" date-mday
full-time = partial-time time-offset
date-time = full-date "T" full-time
Notes importantes
Sensibilité à la casse : Selon [ABNF] et ISO8601, les caractères "T" et "Z" dans cette syntaxe peuvent également être respectivement en minuscules "t" ou "z".
Les spécifications qui utilisent ce format dans des environnements où la casse est significative (comme XML) peuvent (MAY) restreindre davantage la syntaxe de date/heure de sorte que les lettres 'T' et 'Z' utilisées dans la syntaxe de date/heure doivent toujours être en majuscules. Les applications qui génèrent ce format devraient (SHOULD) utiliser des lettres majuscules.
Délimiteurs : ISO 8601 définit la date et l'heure séparées par "T". Les applications utilisant cette syntaxe peuvent (MAY) choisir, pour des raisons de lisibilité, de spécifier un full-date et un full-time séparés par (par exemple) un caractère espace.
Exemples de format
Format standard :
2002-07-15T10:30:00Z
2002-07-15T10:30:00.123Z
2002-07-15T10:30:00+08:00
2002-07-15T10:30:00-04:00
Avec secondes fractionnaires :
2002-07-15T10:30:00.123456Z
2002-07-15T10:30:00.52Z
Variantes lisibles (non standard mais autorisées) :
2002-07-15 10:30:00Z
2002-07-15t10:30:00z
5.7. Restrictions
L'élément grammatical date-mday représente le numéro de jour dans le mois actuel. La valeur maximale varie en fonction du mois et de l'année :
| Numéro de mois | Mois/Année | Maximum date-mday |
|---|---|---|
| 01 | Janvier (January) | 31 |
| 02 | Février, normal (February, normal) | 28 |
| 02 | Février, année bissextile (February, leap year) | 29 |
| 03 | Mars (March) | 31 |
| 04 | Avril (April) | 30 |
| 05 | Mai (May) | 31 |
| 06 | Juin (June) | 30 |
| 07 | Juillet (July) | 31 |
| 08 | Août (August) | 31 |
| 09 | Septembre (September) | 30 |
| 10 | Octobre (October) | 31 |
| 11 | Novembre (November) | 30 |
| 12 | Décembre (December) | 31 |
Secondes intercalaires
L'élément grammatical time-second peut (MAY) avoir la valeur "60" à la fin des mois au cours desquels une seconde intercalaire se produit. Les secondes intercalaires sont utilisées pour maintenir l'UTC proche du temps de rotation de la Terre. Voir l'Annexe D pour plus d'informations sur les secondes intercalaires.
Exemples de secondes intercalaires :
1990-12-31T23:59:60Z ✅ Valide (seconde intercalaire le 31 décembre 1990)
1990-12-31T23:59:61Z ❌ Invalide (maximum est 60)
1990-06-15T23:59:60Z ❌ Invalide (secondes intercalaires uniquement en fin de mois)
5.8. Examples (Exemples)
Voici quelques exemples d'horodatages de date/heure RFC 3339 valides :
1985-04-12T23:20:50.52Z
Représente : 12 avril 1985, 23:20:50.52 UTC
1996-12-19T16:39:57-08:00
Représente : 19 décembre 1996, 16:39:57 Heure du Pacifique (PST)
UTC équivalent : 1996-12-20T00:39:57Z
1990-12-31T23:59:60Z
Représente : Seconde intercalaire le 31 décembre 1990
1990-12-31T15:59:60-08:00
Représente : Seconde intercalaire le 31 décembre 1990 en PST
UTC équivalent : 1990-12-31T23:59:60Z
1937-01-01T12:00:27.87+00:20
Représente : 1er janvier 1937, 12:00:27.87, UTC+00:20
(Exemple de fuseau horaire historique)
Exemples invalides
❌ 1985-04-12 (heure manquante)
❌ 23:20:50.52Z (date manquante)
❌ 1985-04-12 23:20:50.52Z (devrait utiliser 'T' pas espace, bien que certaines implémentations l'autorisent)
❌ 1985-04-32T23:20:50.52Z (date invalide : avril n'a pas de 32e jour)
❌ 1985-02-29T23:20:50.52Z (date invalide : 1985 n'est pas une année bissextile)
Recommandation d'implémentation : Toujours générer le format standard (en utilisant le délimiteur 'T' et 'Z' en majuscule), mais analyser de manière libérale (accepter 't', 'z' et éventuellement les délimiteurs d'espace).
6. Références
Normative References (Références normatives)
[ABNF]
Crocker, D. and P. Overell, "Augmented BNF for Syntax Specifications: ABNF", RFC 2234, November 1997.
[ISO8601]
"Data elements and interchange formats -- Information interchange -- Representation of dates and times", ISO 8601:1988(E), International Organization for Standardization, June 1988.
Remarque : ISO 8601:1988 a été mis à jour par ISO 8601:2000, qui à son tour a été mis à jour par ISO 8601:2004. RFC 3339 est basé sur la version de 1988.
[RFC2119]
Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, March 1997.
Informative References (Références informatives)
[IMAIL]
Crocker, D., "Standard for the Format of Arpa Internet Text Messages", STD 11, RFC 822, August 1982.
[IMAIL-UPDATE]
Resnick, P., "Internet Message Format", RFC 2822, April 2001.
[HOST-REQ]
Braden, R., "Requirements for Internet Hosts -- Application and Support", STD 3, RFC 1123, October 1989.
[NTP]
Mills, D., "Network Time Protocol (Version 3) Specification, Implementation and Analysis", RFC 1305, March 1992.
[ITU-R-TF]
"Standard-frequency and time-signal emissions", ITU-R Recommendation TF.460-4, 1986.
[UNICODE]
The Unicode Consortium, "The Unicode Standard", Version 3.0, Reading, MA, Addison-Wesley, 2000, ISBN 0-201-61633-5.
Documents RFC connexes
Documents prédécesseurs
- RFC 822 - Format de courrier électronique (Standard for the Format of ARPA Internet Text Messages)
- RFC 2822 - Format de message Internet (Met à jour RFC 822)
Normes connexes
- RFC 2234 - Spécification de syntaxe ABNF
- RFC 2119 - Définition des mots-clés RFC
- RFC 1305 - Protocole de temps réseau (NTP)
Mises à jour ultérieures
- RFC 4287 - Format de syndication Atom (utilise les horodatages RFC 3339)
- RFC 7493 - Format de message I-JSON (recommande RFC 3339)
- RFC 8259 - Format d'échange de données JSON (recommande RFC 3339 pour date-heure)
Normes externes
Série ISO 8601
- ISO 8601:1988 - Version sur laquelle ce RFC est basé
- ISO 8601:2000 - Première révision
- ISO 8601:2004 - Deuxième révision
- ISO 8601-1:2019 - Version la plus récente, Partie 1 : Règles de base
- ISO 8601-2:2019 - Version la plus récente, Partie 2 : Extensions
Autres normes connexes
- IETF BCP 14 - Meilleure pratique actuelle composée de RFC 2119 et RFC 8174
- W3C Date and Time Formats - Basé sur ISO 8601 et RFC 3339
- ECMA-262 - Format de chaîne date-heure JavaScript (basé sur ISO 8601 simplifié)
Applications pratiques
Le format RFC 3339 est largement utilisé dans :
Protocoles Internet :
- En-tête HTTP Date (bien que HTTP utilise un format différent défini dans RFC 7231)
- Horodatages de flux Atom/RSS
- Horodatages d'API JSON
- Type dateTime du schéma XML
Langages de programmation :
- JavaScript
Date.toISOString() - Python
datetime.isoformat() - Java
Instant.toString() - Go
time.RFC3339
Bases de données :
- PostgreSQL
TIMESTAMPTZ - MongoDB
ISODate - MySQL
TIMESTAMPwith timezone
Remarque : Bien que RFC 3339 soit basé sur ISO 8601:1988, il s'agit d'un profil (sous-ensemble) d'ISO 8601, et non d'une implémentation complète. RFC 3339 est plus strict et simplifié pour assurer l'interopérabilité dans les protocoles Internet.
7. Considérations de sécurité
Étant donné que ce document spécifie uniquement un format pour représenter les dates et les heures, les problèmes de sécurité discutés ici se limitent à l'impact que les horloges non synchronisées ont sur les fonctionnalités de sécurité.
Risques de sécurité des horloges non synchronisées
1. Échecs de validation de certificat
Les horloges non synchronisées peuvent faire apparaître incorrectement les certificats comme expirés ou pas encore valides.
Exemple de risque :
Horloge client : 2002-07-14T10:00:00Z (1 jour en avance)
Validité du certificat :
Not Before : 2002-07-15T00:00:00Z
Not After : 2003-07-15T23:59:59Z
Résultat : Le client rejette un certificat valide ❌
Cas opposé :
Horloge client : 2003-07-20T10:00:00Z (2 ans en retard)
Validité du certificat :
Not After : 2003-07-15T23:59:59Z (déjà expiré)
Résultat : Le client accepte un certificat expiré ⚠️ Risque de sécurité !
2. Contournement de vérification d'horodatage
De nombreux protocoles de sécurité s'appuient sur des horodatages pour prévenir les attaques par rejeu.
Exemple d'attaque par rejeu :
Requête légitime interceptée par l'attaquant :
POST /transfer HTTP/1.1
Timestamp : 2002-07-15T10:00:00Z
Amount : $1000
Signature : valid_signature
Si l'horloge du serveur a 1 heure de retard, l'attaquant peut rejouer cette requête
3. Journaux d'audit non fiables
Si les horodatages des journaux sont inexacts, l'audit de sécurité et l'analyse forensique deviennent impossibles ou peu fiables.
Scénario problématique :
Journaux du serveur A : 2002-07-15T10:00:00Z - Intrusion détectée
Journaux du serveur B : 2002-07-15T09:45:00Z - Connexion anormale (en fait plus tard que A, mais horloge en retard)
Impossible d'établir une chronologie d'attaque précise ❌
Recommandations de protection
Utiliser NTP (Network Time Protocol)
Tous les systèmes connectés à Internet devraient (SHOULD) utiliser NTP ou des protocoles similaires de synchronisation de l'heure.
Exemple de configuration NTP :
# Configurer le serveur NTP
ntpdate -u time.nist.gov
# Activer le démon ntpd
systemctl enable ntpd
systemctl start ntpd
# Vérifier l'état de synchronisation
ntpq -p
Tolérance d'horodatage
Implémenter des fenêtres de tolérance raisonnables lors de la validation des horodatages.
Exemple d'implémentation :
def is_timestamp_valid(timestamp, max_age_seconds=300):
"""Vérifier que l'horodatage est dans une fenêtre temporelle acceptable"""
now = datetime.now(timezone.utc)
tolerance = timedelta(seconds=max_age_seconds)
# Permettre ±5 minutes de décalage d'horloge
if abs(now - timestamp) > tolerance:
return False
return True
Utiliser des sources de temps fiables
Serveurs NTP publics recommandés :
time.nist.gov (Institut national des normes et de la technologie des États-Unis)
time.google.com (Google)
time.apple.com (Apple)
time.cloudflare.com (Cloudflare)
pool.ntp.org (Projet NTP Pool)
Meilleures pratiques de validation de certificat
# Considérer le décalage d'horloge lors de la validation des certificats
def verify_certificate(cert, clock_tolerance=timedelta(minutes=5)):
now = datetime.now(timezone.utc)
# Vérifier Not Before avec indulgence
if now < (cert.not_before - clock_tolerance):
raise CertificateNotYetValid()
# Vérifier Not After strictement (sécurité d'abord)
if now > cert.not_after:
raise CertificateExpired()
Problèmes de sécurité liés au fuseau horaire
1. Attaques par confusion de fuseau horaire
Un traitement incohérent des fuseaux horaires peut conduire à des contournements de sécurité.
Exemple de vulnérabilité :
Soumission utilisateur : 2002-07-15T23:00:00-08:00
Système A analyse comme : 2002-07-16T07:00:00Z (correct)
Système B analyse comme : 2002-07-15T23:00:00Z (incorrect, ignore le fuseau horaire)
Si le système B est utilisé pour les décisions de contrôle d'accès, peut permettre un accès non autorisé
2. Limites de l'heure d'été
Des ambiguïtés ou des problèmes de sécurité peuvent survenir lors des transitions vers l'heure d'été.
Moments à risque :
10 mars 2002 2:00 → 3:00 (saut d'1 heure)
Problème : 2:30 n'existe pas, comment gérer cet horodatage ?
3 novembre 2002 2:00 → 1:00 (répétition d'1 heure)
Problème : 1:30 se produit deux fois, lequel est correct ?
Solution RFC 3339 : Utiliser le décalage UTC pour éliminer l'ambiguïté :
✅ 2002-11-03T01:30:00-05:00 (EDT, avant la fin de l'heure d'été)
✅ 2002-11-03T01:30:00-04:00 (EST, après la fin de l'heure d'été)
Impact sécuritaire des secondes intercalaires
Bien que rares, une mauvaise gestion des secondes intercalaires peut causer des problèmes.
Problèmes potentiels :
1990-12-31T23:59:60Z (seconde intercalaire)
Si le système ne prend pas en charge les secondes intercalaires :
- Peut rejeter des horodatages valides
- Peut causer des erreurs de tri
- Peut causer des différences de temps d'1 seconde
Recommandation :
# Gérer les secondes intercalaires avec indulgence
def parse_timestamp(ts_string):
try:
return datetime.fromisoformat(ts_string)
except ValueError as e:
# Vérifier si c'est une seconde intercalaire (seconde est 60)
if ':60Z' in ts_string or ':60+' in ts_string or ':60-' in ts_string:
# Convertir 60 secondes en 00 secondes de la minute suivante
ts_string = ts_string.replace(':60', ':59')
return datetime.fromisoformat(ts_string) + timedelta(seconds=1)
raise
Liste de contrôle de sécurité
Lors de l'implémentation des horodatages RFC 3339, s'assurer de :
- Synchroniser les horloges système avec NTP
- Toujours utiliser l'UTC pour le stockage et la comparaison internes
- Implémenter une tolérance raisonnable lors de la validation des horodatages
- Gérer correctement les décalages de fuseau horaire
- Enregistrer tous les événements de sécurité liés au temps
- Auditer régulièrement la précision de l'horloge système
- Considérer le décalage d'horloge dans la validation de certificat
- Implémenter la protection contre les attaques par rejeu (nonce + horodatage)
- Analyser avec indulgence, générer strictement
- Tester les cas limites (secondes intercalaires, années bissextiles, fins de mois)
Principe clé : Ne pas s'appuyer sur des horodatages fournis par le client pour des décisions de sécurité critiques. Toujours utiliser des sources de temps fiables côté serveur.
Appendix A. ISO 8601 Collected ABNF
Cette information est basée sur la version 1988 d'ISO 8601. Il peut y avoir quelques changements dans la révision de 2000.
Explication
ISO 8601 ne spécifie pas de grammaire formelle pour les formats de date et d'heure qu'il définit. Ce qui suit est une tentative de créer une grammaire formelle à partir d'ISO 8601. Ceci est fourni à titre informatif uniquement et peut contenir des erreurs. ISO 8601 reste la référence faisant autorité.
Ambiguïtés et interprétations
Notez qu'en raison d'ambiguïtés dans ISO 8601, une certaine interprétation a été nécessaire :
-
Mélange de formats de base et étendus : ISO 8601 n'est pas clair si le mélange de format de base et étendu est autorisé. Cette grammaire permet le mélange.
-
24 heures : ISO 8601 n'est pas clair si l'heure 24 n'est autorisée que si les minutes et les secondes sont 0. Cette grammaire suppose que l'heure 24 est autorisée dans n'importe quel contexte.
-
Restrictions de date : Les restrictions de la section 5.7 concernant date-mday s'appliquent.
-
Délimiteur "T" : ISO 8601 spécifie que "T" peut être omis dans certaines circonstances. Cette grammaire requiert "T" pour éviter l'ambiguïté.
-
Point décimal : ISO 8601 exige (dans la section 5.3.1.3) que si la fraction décimale est inférieure à 1, elle doit être précédée d'un "0". L'annexe B.2 d'ISO 8601 donne des exemples avec des fractions décimales non précédées de "0". Cette grammaire suppose que la section 5.3.1.3 est correcte et l'annexe B.2 est erronée.
Grammaire ABNF complète ISO 8601
date-century = 2DIGIT ; 00-99
date-decade = DIGIT ; 0-9
date-subdecade = DIGIT ; 0-9
date-year = date-decade date-subdecade
date-fullyear = date-century date-year
date-month = 2DIGIT ; 01-12
date-wday = DIGIT ; 1-7 ; 1 is Monday, 7 is Sunday
date-mday = 2DIGIT ; 01-28, 01-29, 01-30, 01-31
date-yday = 3DIGIT ; 001-365, 001-366
date-week = 2DIGIT ; 01-52, 01-53
datepart-fullyear = [date-century] date-year ["-"]
datepart-ptyear = "-" [date-subdecade ["-"]]
datepart-wkyear = datepart-fullyear / datepart-ptyear
dateopt-century = "-" / date-century
dateopt-fullyear = "-" / datepart-fullyear
dateopt-year = "-" / (date-year ["-"])
dateopt-month = "-" / (date-month ["-"])
dateopt-week = "-" / (date-week ["-"])
datespec-full = datepart-fullyear date-month ["-"] date-mday
datespec-year = date-century / dateopt-century date-year
datespec-month = "-" dateopt-year date-month [["-"] date-mday]
datespec-mday = "--" dateopt-month date-mday
datespec-week = datepart-wkyear "W"
(date-week / dateopt-week date-wday)
datespec-wday = "---" date-wday
datespec-yday = dateopt-fullyear date-yday
date = datespec-full
/ datespec-year
/ datespec-month
/ datespec-mday
/ datespec-week
/ datespec-wday
/ datespec-yday
time-hour = 2DIGIT ; 00-24
time-minute = 2DIGIT ; 00-59
time-second = 2DIGIT ; 00-58, 00-59, 00-60
time-fraction = ("," / ".") 1*DIGIT
time-numoffset = ("+" / "-") time-hour [[":"] time-minute]
time-zone = "Z" / time-numoffset
timeopt-hour = "-" / (time-hour [":"])
timeopt-minute = "-" / (time-minute [":"])
timespec-hour = time-hour [[":"] time-minute [[":"] time-second]]
timespec-minute = timeopt-hour time-minute [[":"] time-second]
timespec-second = "-" timeopt-minute time-second
timespec-base = timespec-hour / timespec-minute / timespec-second
time = timespec-base [time-fraction] [time-zone]
iso-date-time = date "T" time
RFC 3339 vs ISO 8601 complet
RFC 3339 est un sous-ensemble restreint d'ISO 8601, pas une implémentation complète :
| Fonctionnalité | ISO 8601 | RFC 3339 |
|---|---|---|
| Format de base (20020715) | ✅ Pris en charge | ❌ Non pris en charge |
| Format étendu (2002-07-15) | ✅ Pris en charge | ✅ Pris en charge |
| Dates de semaine (2002-W29-1) | ✅ Pris en charge | ❌ Non pris en charge |
| Dates ordinales (2002-196) | ✅ Pris en charge | ❌ Non pris en charge |
| Dates partielles (2002-07) | ✅ Pris en charge | ❌ Non pris en charge |
| 24 heures (2002-07-16T24:00:00) | ✅ Pris en charge | ❌ Non pris en charge |
| Fuseau horaire "Z" | ✅ Pris en charge | ✅ Pris en charge |
| Décalage de fuseau horaire numérique | ✅ Pris en charge | ✅ Pris en charge (obligatoire) |
| Secondes fractionnaires | ✅ Pris en charge | ✅ Pris en charge |
Raisons de la simplification de RFC 3339
RFC 3339 a choisi un sous-ensemble simplifié pour :
- Interopérabilité : Réduire les variations d'implémentation
- Clarté : Éviter l'ambiguïté
- Complétude : Exiger des informations complètes de date-heure
- Simplicité : Plus facile à implémenter et à tester
Remarque : Si la fonctionnalité complète d'ISO 8601 (comme les dates de semaine) est nécessaire, consultez directement la norme ISO 8601. RFC 3339 se concentre sur les cas d'utilisation d'horodatage les plus courants dans les protocoles Internet.
Appendix B. Jour de la semaine
Cette annexe montre comment calculer le jour de la semaine à partir de n'importe quelle date du calendrier grégorien. Ceci est important pour comprendre pourquoi RFC 3339 n'inclut pas d'informations sur le jour de la semaine—parce qu'il peut être calculé précisément.
Congruence de Zeller
Un algorithme couramment utilisé pour calculer le jour de la semaine est la congruence de Zeller, inventée par Christian Zeller en 1882.
Formule
h = (q + ⌊13(m+1)/5⌋ + K + ⌊K/4⌋ + ⌊J/4⌋ - 2J) mod 7
Où :
h: Jour de la semaine (0 = samedi, 1 = dimanche, 2 = lundi, ..., 6 = vendredi)q: Jour du mois (1-31)m: Mois (3-14, où 3 = mars, 4 = avril, ..., 12 = décembre, 13 = janvier, 14 = février)K: Année du siècle (year % 100)J: Siècle (⌊year/100⌋)⌊x⌋: Fonction plancher
Remarque : Janvier et février sont traités comme les 13e et 14e mois de l'année précédente.
Implémentation Python
def day_of_week_zeller(year, month, day):
"""
Calculer le jour de la semaine en utilisant la formule de Zeller
Retourne : 0=samedi, 1=dimanche, ..., 6=vendredi
"""
# Janvier et février sont traités comme mois 13 et 14 de l'année précédente
if month < 3:
month += 12
year -= 1
q = day
m = month
K = year % 100
J = year // 100
h = (q + (13 * (m + 1)) // 5 + K + K // 4 + J // 4 - 2 * J) % 7
# Convertir au format commun : 0=lundi, ..., 6=dimanche
# Zeller : 0=Sam, 1=Dim, 2=Lun, 3=Mar, 4=Mer, 5=Jeu, 6=Ven
# Ajuster à : 0=Lun, 1=Mar, 2=Mer, 3=Jeu, 4=Ven, 5=Sam, 6=Dim
return (h + 5) % 7
def day_name(year, month, day):
"""Retourner le nom du jour de la semaine"""
days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday',
'Friday', 'Saturday', 'Sunday']
return days[day_of_week_zeller(year, month, day)]
# Exemples
print(day_name(2002, 7, 15)) # Monday
print(day_name(2000, 1, 1)) # Saturday
print(day_name(1999, 12, 31)) # Friday
Algorithme plus simple
Pour les implémentations de programmation, un algorithme plus intuitif peut être utilisé :
def day_of_week_simple(year, month, day):
"""
Calcul simplifié du jour de la semaine
Retourne : 0=lundi, ..., 6=dimanche
"""
# Jours cumulés avant chaque mois (année non bissextile)
t = [0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4]
if month < 3:
year -= 1
y = year % 100
c = year // 100
return (y + y // 4 + c // 4 - 2 * c + t[month - 1] + day) % 7
Implémentation JavaScript
function dayOfWeek(year, month, day) {
// L'objet Date JavaScript calcule automatiquement le jour de la semaine
const date = new Date(year, month - 1, day);
const days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday',
'Thursday', 'Friday', 'Saturday'];
return days[date.getDay()];
}
// Exemples
console.log(dayOfWeek(2002, 7, 15)); // Monday
Exemples de vérification
| Date | Jour de la semaine | Vérifié |
|---|---|---|
| 2002-07-15 | Lundi (Monday) | ✅ |
| 2000-01-01 | Samedi (Saturday) | ✅ |
| 1999-12-31 | Vendredi (Friday) | ✅ |
| 1985-04-12 | Vendredi (Friday) | ✅ |
| 1990-12-31 | Lundi (Monday) | ✅ |
Pourquoi RFC 3339 n'inclut pas le jour de la semaine
1. Information redondante
Le jour de la semaine peut être calculé précisément à partir de la date, donc l'inclure introduit des incohérences potentielles :
Exemple incorrect :
"Monday, 2002-07-16T10:00:00Z"
Problème : 2002-07-16 est en fait mardi, pas lundi
Auquel faut-il faire confiance ? Jour de la semaine ou date ?
2. Complexité accrue
Les analyseurs doivent gérer la validation et les incohérences entre le jour de la semaine et la date.
3. Problèmes de localisation
Les noms des jours de la semaine diffèrent selon les langues :
Anglais : Monday, Tuesday, Wednesday, ...
Français : Lundi, Mardi, Mercredi, ...
Chinois : 星期一, 星期二, 星期三, ...
4. N'affecte pas le point temporel
Le jour de la semaine n'affecte pas la détermination du point temporel, c'est seulement pour la lisibilité humaine.
Recommandation
Si vous devez afficher le jour de la semaine :
from datetime import datetime
# Analyser l'horodatage RFC 3339
timestamp = "2002-07-15T10:00:00Z"
dt = datetime.fromisoformat(timestamp.replace('Z', '+00:00'))
# Calculer et afficher le jour de la semaine
day_name = dt.strftime('%A')
print(f"{timestamp} is a {day_name}")
# Sortie : 2002-07-15T10:00:00Z is a Monday
Conclusion : Puisque le jour de la semaine peut être calculé précisément et de manière déterministe à partir de la date, l'inclure dans le format d'horodatage n'est pas seulement inutile mais nuisible.
Appendix D. Secondes intercalaires
Cette annexe détaille le concept, l'historique et la gestion des secondes intercalaires dans RFC 3339.
Qu'est-ce qu'une seconde intercalaire ?
Une seconde intercalaire est occasionnellement ajoutée au Temps Universel Coordonné (UTC) pour maintenir l'UTC synchronisé avec la rotation de la Terre.
Pourquoi les secondes intercalaires ?
Temps Atomique International (TAI) :
- Basé sur des horloges atomiques, extrêmement stable
- 1 seconde = 9 192 631 770 oscillations d'atomes de césium
- Ne change jamais
Rotation de la Terre :
- Pas parfaitement uniforme
- Affectée par la friction des marées
- Ralentit progressivement (~1,4ms/jour par siècle)
- Vitesse imprévisible
Fonctionnement des secondes intercalaires
Exemple de seconde intercalaire positive
Fin de mois normale :
23:59:58
23:59:59
00:00:00 (jour suivant)
Avec seconde intercalaire positive :
23:59:58
23:59:59
23:59:60 ← Seconde intercalaire !
00:00:00 (jour suivant)
Représentation RFC 3339
1990-12-31T23:59:60Z ✅ Valide (seconde intercalaire le 31 déc 1990)
2012-06-30T23:59:60Z ✅ Valide (seconde intercalaire le 30 juin 2012)
2015-06-30T23:59:60Z ✅ Valide (seconde intercalaire le 30 juin 2015)
2016-12-31T23:59:60Z ✅ Valide (seconde intercalaire le 31 déc 2016)
Secondes intercalaires historiques
Depuis l'introduction de l'UTC en 1972 :
Date Heure UTC TAI-UTC
1972-06-30 23:59:60Z +11s
1972-12-31 23:59:60Z +12s
1990-12-31 23:59:60Z +26s
2012-06-30 23:59:60Z +35s
2015-06-30 23:59:60Z +36s
2016-12-31 23:59:60Z +37s (la plus récente)
Note :
- Secondes intercalaires ajoutées uniquement le 30 juin ou le 31 décembre
- 27 secondes intercalaires depuis 1972
- La dernière était le 31 décembre 2016
Point clé : RFC 3339 autorise les secondes intercalaires mais la plupart des implémentations les mappent à la seconde suivante pour la compatibilité pratique.