Cette page a été traduite à partir de l'anglais par la communauté. Vous pouvez contribuer en rejoignant la communauté francophone sur MDN Web Docs.

View in English Always switch to English

Temporal

Limited availability

Cette fonctionnalité n'est pas Compatible car elle ne fonctionne pas dans certains des navigateurs les plus utilisés.

L'objet Temporal permet la gestion des dates et heures dans divers scénarios, y compris la représentation intégrée des fuseaux horaires et des calendriers, les conversions d'heures murales, les opérations arithmétiques, le formatage, et plus encore. Il est conçu comme un remplacement complet de l'objet Date.

Description

Contrairement à la plupart des objets globaux, Temporal n'est pas un constructeur. Vous ne pouvez pas utiliser l'opérateur new ni invoquer l'objet Temporal comme une fonction. Toutes les propriétés et méthodes de Temporal sont statiques (comme pour l'objet Math).

Temporal possède une API complexe et puissante. Il expose plus de 200 méthodes utilitaires par l'intermédiaire de plusieurs classes, ce qui peut sembler très complexe. Nous proposons un aperçu général de la façon dont ces API sont liées entre elles.

Contexte et concepts

JavaScript dispose de l'objet Date pour gérer les dates et les heures depuis ses débuts. Cependant, l'API Date est basée sur la classe java.util.Date mal conçue de Java, remplacée au début des années 2010 ; mais, en raison de l'objectif de compatibilité ascendante de JavaScript, Date est restée dans le langage.

La leçon importante à prefacer l'ensemble de cette introduction est que la gestion des dates est complexe. La plupart des problèmes de Date peuvent être corrigés en ajoutant des méthodes, mais un défaut fondamental de conception subsiste : il expose tellement de méthodes sur le même objet que les développeur·euse·s sont souvent confus·e·s quant à ce qu'il faut utiliser, ce qui conduit à des pièges inattendus. Une API bien conçue doit non seulement faire plus, mais aussi faire moins à chaque niveau d'abstraction, car prévenir les mauvais usages est aussi important que de permettre des cas d'utilisation.

Les objets Date portent deux casquettes simultanément :

  • En tant qu'horodatage : le nombre de millisecondes ou de nanosecondes écoulées depuis un moment précis (appelé l'epoch).
  • En tant que combinaison de composants : année, mois, jour, heure, minute, seconde, milliseconde et nanoseconde. Les identificateurs d'année, de mois et de jour n'ont de sens que s'ils sont considérés par rapport à un système de calendrier. L'ensemble de la combinaison correspond à un instant unique de l'histoire lorsqu'il est associé à un fuseau horaire. Les objets Date fournissent des méthodes pour lire et modifier ces composants.

Les fuseaux horaires sont à l'origine d'un grand nombre de bugs liés aux dates. Lorsqu'on interagit avec un Date par le modèle « combinaison de composants », l'heure ne peut être que dans deux fuseaux : UTC et local (appareil), et il n'est pas possible de définir un fuseau arbitraire. Il manque également le concept de « sans fuseau horaire » : on parle alors de date civile (pour les dates) ou d'heure murale (pour les heures), qui est une heure que l'on « lit sur un calendrier ou une horloge ». Par exemple, si vous réglez une alarme quotidienne, vous voudrez la régler sur « 8:00AM » indépendamment de l'heure d'été ou de vos déplacements vers un autre fuseau horaire.

Un second défaut de Date est l'absence d'un système de calendrier. Beaucoup connaissent peut-être le calendrier grégorien, où il existe deux ères, BC et AD ; il y a 12 mois ; chaque mois compte un nombre de jours différent ; il y a une année bissextile tous les 4 ans ; et ainsi de suite. Cependant, certains de ces concepts peuvent ne pas s'appliquer lorsque vous travaillez avec un autre système de calendrier, comme le calendrier hébraïque, le calendrier chinois, le calendrier japonais, etc. Avec Date, vous ne pouvez travailler qu'avec le modèle du calendrier grégorien.

Il existe d'autres héritages indésirables de Date, tels que le fait que tous les mutateurs modifient l'objet (ce qui provoque souvent des effets secondaires indésirables), le format de chaîne date-heure impossible à analyser de façon cohérente, etc. En fin de compte, la meilleure solution est de construire une nouvelle API depuis le début, ce qui est le rôle de Temporal.

Aperçu de l'API

Temporal est un espace de noms, comme Intl. Il contient plusieurs classes et espaces de noms, chacun étant conçu pour gérer un aspect spécifique de la gestion des dates et des heures. Les classes peuvent être regroupées comme suit :

  • Représentation d'une durée temporelle (une différence entre deux points dans le temps) : Temporal.Duration
  • Représentation d'un point dans le temps :
    • Représentation d'un instant unique dans l'histoire :
    • Représentation d'une date/heure sans fuseau horaire (toutes préfixées par « Plain ») :

De plus, il existe également un autre espace de noms utilitaire, Temporal.Now, qui fournit des méthodes pour obtenir l'heure actuelle dans différents formats.

Classes d'interface partagée

Il existe de nombreuses classes dans l'espace de noms Temporal, mais elles partagent de nombreuses méthodes similaires. Le tableau suivant répertorie toutes les méthodes de chaque classe (à l'exception des méthodes de conversion) :

Instant ZonedDateTime PlainDateTime PlainDate PlainTime PlainYearMonth PlainMonthDay
Construction Instant()
Instant.from()
Instant.fromEpochMilliseconds()
Instant.fromEpochNanoseconds()
ZonedDateTime()
ZonedDateTime.from()
PlainDateTime()
PlainDateTime.from()
PlainDate()
PlainDate.from()
PlainTime()
PlainTime.from()
PlainYearMonth()
PlainYearMonth.from()
PlainMonthDay()
PlainMonthDay.from()
Mise à jour N/A with()
withCalendar()
withTimeZone()
withPlainTime()
with()
withCalendar()
withPlainTime()
with()
withCalendar()
with() with() with()
Arithmétique add()
subtract()
since()
until()
add()
subtract()
since()
until()
add()
subtract()
since()
until()
add()
subtract()
since()
until()
add()
subtract()
since()
until()
add()
subtract()
since()
until()
N/A
Arrondi round() round() round() N/A round() N/A N/A
Comparaison equals()
Instant.compare()
equals()
ZonedDateTime.compare()
equals()
PlainDateTime.compare()
equals()
PlainDate.compare()
equals()
PlainTime.compare()
equals()
PlainYearMonth.compare()
equals()
Sérialisation toJSON()
toLocaleString()
toString()
valueOf()
toJSON()
toLocaleString()
toString()
valueOf()
toJSON()
toLocaleString()
toString()
valueOf()
toJSON()
toLocaleString()
toString()
valueOf()
toJSON()
toLocaleString()
toString()
valueOf()
toJSON()
toLocaleString()
toString()
valueOf()
toJSON()
toLocaleString()
toString()
valueOf()

Le tableau suivant résume les propriétés disponibles pour chaque classe, vous donnant une idée des informations que chaque classe peut représenter.

Instant ZonedDateTime PlainDateTime PlainDate PlainTime PlainYearMonth PlainMonthDay
Calendrier N/A calendarId calendarId calendarId N/A calendarId calendarId
Associé à l'année N/A era
eraYear
year
inLeapYear
monthsInYear
daysInYear
era
eraYear
year
inLeapYear
monthsInYear
daysInYear
era
eraYear
year
inLeapYear
monthsInYear
daysInYear
N/A era
eraYear
year
inLeapYear
monthsInYear
daysInYear
N/A
Associé au mois N/A month
monthCode
daysInMonth
month
monthCode
daysInMonth
month
monthCode
daysInMonth
N/A month
monthCode
daysInMonth
monthCode
Associé à la semaine N/A weekOfYear
yearOfWeek
daysInWeek
weekOfYear
yearOfWeek
daysInWeek
weekOfYear
yearOfWeek
daysInWeek
N/A N/A N/A
Associé au jour N/A day
dayOfWeek
dayOfYear
day
dayOfWeek
dayOfYear
day
dayOfWeek
dayOfYear
N/A N/A day
Composants temporels N/A hour
minute
second
millisecond
microsecond
nanosecond
hour
minute
second
millisecond
microsecond
nanosecond
N/A hour
minute
second
millisecond
microsecond
nanosecond
N/A N/A
Fuseau horaire N/A timeZoneId
offset
offsetNanoseconds
hoursInDay
getTimeZoneTransition()
startOfDay()
N/A N/A N/A N/A N/A
Temps epoch epochMilliseconds
epochNanoseconds
epochMilliseconds
epochNanoseconds
N/A N/A N/A N/A N/A

Conversion entre les classes

Le tableau ci-dessous résume toutes les méthodes de conversion existant sur chaque classe.

Comment convertir à partir de...
Instant ZonedDateTime PlainDateTime PlainDate PlainTime PlainYearMonth PlainMonthDay
à...Instant/toInstant()Convertir d'abord en ZonedDateTime
ZonedDateTimetoZonedDateTimeISO()/toZonedDateTime()toZonedDateTime()PlainDate#toZonedDateTime() (pass as argument)Convertir d'abord en PlainDate
PlainDateTimeConvertir d'abord en ZonedDateTimetoPlainDateTime()/toPlainDateTime()PlainDate#toPlainDateTime() (pass as argument)
PlainDatetoPlainDate()toPlainDate()/Pas de chevauchement d'informationstoPlainDate()toPlainDate()
PlainTimetoPlainTime()toPlainTime()Pas de chevauchement d'informations/Pas de chevauchement d'informations
PlainYearMonthConvertir d'abord en PlainDatetoPlainYearMonth()Pas de chevauchement d'informations/Convertir d'abord en PlainDate
PlainMonthDaytoPlainMonthDay()Convertir d'abord en PlainDate/

Avec ces tableaux, vous devriez avoir une idée de base de la façon de naviguer dans l'API Temporal.

Calendriers

Un calendrier est une façon d'organiser les jours, généralement en périodes de semaines, de mois, d'années et d'ères. La majeure partie du monde utilise le calendrier grégorien, mais il existe de nombreux autres calendriers, notamment dans des contextes religieux et culturels. Par défaut, tous les objets Temporal sensibles au calendrier utilisent le système de calendrier ISO 8601, qui est basé sur le calendrier grégorien et définit des règles supplémentaires de numérotation des semaines. Intl.supportedValuesOf() liste la plupart des calendriers susceptibles d'être pris en charge par les navigateurs. Nous proposons ici un aperçu de la façon dont les systèmes de calendrier sont formés pour vous aider à comprendre les facteurs qui peuvent varier d'un calendrier à l'autre.

Il existe trois grands évènements périodiques sur Terre : sa révolution autour du soleil (365,242 jours pour un tour), la révolution de la lune autour de la Terre (29,53 jours de nouvelle lune à nouvelle lune), et sa rotation sur son axe (24 heures de lever de soleil à lever de soleil). Chaque culture a la même mesure d'un « jour », soit 24 heures. Les changements occasionnels comme l'heure d'été ne font pas partie du calendrier, mais relèvent des informations du fuseau horaire.

  • Certains calendriers définissent principalement une année comme ayant en moyenne 365,242 jours, en définissant des années de 365 jours et en ajoutant un jour supplémentaire, le jour intercalaire, environ tous les 4 ans. Ensuite, l'année peut être divisée en parties appelées mois. Ces calendriers sont appelés calendriers solaires. Le calendrier grégorien et le calendrier solaire hijri sont des calendriers solaires.
  • Certains calendriers définissent principalement un mois comme ayant en moyenne 29,5 jours, en alternant des mois de 29 et 30 jours. Ensuite, 12 mois peuvent former une année de 354 jours. Ces calendriers sont appelés calendriers lunaires. Le calendrier islamique est un calendrier lunaire. Comme une année lunaire est artificielle et ne correspond pas au cycle des saisons, les calendriers lunaires sont généralement plus rares.
  • Certains calendriers définissent aussi principalement les mois selon les cycles lunaires, comme les calendriers lunaires. Ensuite, pour compenser l'écart de 11 jours avec l'année solaire, un mois supplémentaire, le mois intercalaire, est ajouté environ tous les 3 ans. Ces calendriers sont appelés calendriers lunisolaire. Le calendrier hébraïque et le calendrier chinois sont des calendriers lunisolaire.

Dans Temporal, chaque date selon un système de calendrier est identifiée de façon unique par trois composants : year, month et day. Si year est généralement un entier positif, il peut aussi être nul ou négatif, et il augmente de façon monotone avec le temps. L'année 1 (ou 0, si elle existe) est appelée l'époque du calendrier, et elle est arbitraire pour chaque calendrier. month est un entier positif qui s'incrémente de 1 à chaque fois, en commençant à 1 et en finissant à date.monthsInYear, puis revient à 1 à mesure que l'année avance. day est aussi un entier positif, mais il peut ne pas commencer à 1 ou s'incrémenter de 1 à chaque fois, car des changements politiques peuvent entraîner des jours sautés ou répétés. Mais en général, day augmente de façon monotone et revient à 1 à mesure que le mois avance.

En plus de year, une année peut aussi être identifiée de façon unique par la combinaison de era et eraYear, pour les calendriers qui utilisent des ères. Par exemple, le calendrier grégorien utilise les ères « CE » (ère commune) et « BCE » (avant l'ère commune), et l'année -1 est la même que { era: "bce", eraYear: 2 } (notez que l'année 0 existe toujours pour tous les calendriers ; pour le calendrier grégorien, elle correspond à 1 BCE selon la numérotation astronomique des années (angl.)). era est une chaîne en minuscules, et eraYear est un entier arbitraire qui peut être nul ou négatif, ou même décroître avec le temps (généralement pour l'ère la plus ancienne).

Note : Toujours utiliser era et eraYear ensemble ; n'utilisez pas une propriété sans l'autre. De plus, pour éviter les conflits, n'associez pas year et era/eraYear pour désigner une année. Choisissez une représentation d'année et utilisez-la de façon cohérente.

Faites attention aux hypothèses incorrectes suivantes concernant les années :

  • Ne supposez pas que era et eraYear sont toujours présents ; ils peuvent être undefined.
  • Ne supposez pas que era est une chaîne conviviale ; utilisez toLocaleString() pour formater votre date.
  • Ne supposez pas que deux valeurs year de calendriers différents sont comparables ; utilisez plutôt la méthode statique compare().
  • Ne supposez pas que les années ont 365/366 jours et 12 mois ; utilisez daysInYear et monthsInYear.
  • Ne supposez pas que les années bissextiles (inLeapYear vaut true) ont un jour supplémentaire ; elles peuvent avoir un mois supplémentaire.

En plus de month, un mois dans une année peut aussi être identifié de façon unique par le monthCode. monthCode correspond généralement au nom du mois, mais pas month. Par exemple, dans le cas des calendriers lunisolaire, deux mois ayant le même monthCode, dont l'un appartient à une année bissextile et l'autre non, auront des valeurs month différentes s'ils viennent après le mois intercalaire, en raison de l'insertion d'un mois supplémentaire.

Note : Pour éviter les conflits, n'associez pas month et monthCode pour désigner un mois. Choisissez une représentation de mois et utilisez-la de façon cohérente. month est plus utile si vous avez besoin de l'ordre des mois dans une année (par exemple, lors d'une boucle sur les mois), tandis que monthCode est plus utile si vous avez besoin du nom du mois (par exemple, pour stocker des anniversaires).

Faites attention aux hypothèses incorrectes suivantes concernant les mois :

  • Ne supposez pas que monthCode et month correspondent toujours.
  • Ne supposez pas le nombre de jours dans un mois ; utilisez daysInMonth.
  • Ne supposez pas que monthCode est une chaîne conviviale ; utilisez toLocaleString() pour formater votre date.
  • En général, n'enregistrez pas le nom des mois dans un tableau ou un objet. Même si monthCode correspond généralement au nom du mois dans un calendrier, il est recommandé de toujours calculer le nom du mois, par exemple avec date.toLocaleString("fr-FR", { calendar: date.calendarId, month: "long" }).

En plus de day (qui est un index basé sur le mois), un jour dans une année peut aussi être identifié de façon unique par le dayOfYear. dayOfYear est un entier positif qui s'incrémente de 1 à chaque fois, en commençant à 1 et en finissant à date.daysInYear.

Le concept de « semaine » n'est lié à aucun évènement astronomique, mais est une construction culturelle. Bien que la longueur la plus courante soit de 7 jours, les semaines peuvent aussi avoir 4, 5, 6, 8 jours ou plus — ou même ne pas avoir de nombre fixe de jours. Pour obtenir le nombre exact de jours de la semaine d'une date, utilisez la propriété daysInWeek de la date. Temporal identifie les semaines par la combinaison de weekOfYear et yearOfWeek. weekOfYear est un entier positif qui s'incrémente de 1 à chaque fois, en commençant à 1, puis revient à 1 à mesure que l'année avance. yearOfWeek est généralement identique à year, mais peut différer au début ou à la fin de chaque année, car une semaine peut chevaucher deux années, et yearOfWeek choisit l'une des deux années selon les règles du calendrier.

Note : Toujours utiliser weekOfYear et yearOfWeek ensemble ; n'utilisez pas weekOfYear et year.

Faites attention aux hypothèses incorrectes suivantes concernant les semaines :

  • Ne supposez pas que weekOfYear et yearOfWeek sont toujours présents ; ils peuvent être undefined.
  • Ne supposez pas que les semaines font toujours 7 jours ; utilisez daysInWeek.
  • Notez que l'API Temporal actuelle ne prend pas en charge les dates année-semaine, vous ne pouvez donc pas construire de dates avec ces propriétés ni les sérialiser dans ce format. Ce sont uniquement des propriétés informatives.

Format RFC 9557

Toutes les classes Temporal peuvent être sérialisées et désérialisées en utilisant le format défini dans la RFC 9557 (angl.), qui est basé sur ISO 8601 / RFC 3339 (angl.). Le format, dans sa forme complète, est le suivant (les espaces ne sont là que pour la lisibilité et ne doivent pas être présents dans la chaîne de caractères réelle) :

YYYY-MM-DD T HH:mm:ss.sssssssss Z/±HH:mm [time_zone_id] [u-ca=calendar_id]

Chaque classe a des exigences différentes concernant la présence de chaque composant, vous trouverez donc une section intitulée « Format RFC 9557 » dans la documentation de chaque classe, qui précise le format reconnu par cette classe.

Ceci est très similaire au format de chaîne date-heure utilisé par Date, qui est aussi basé sur ISO 8601. La principale nouveauté est la possibilité de définir des composants de microsecondes et nanosecondes, ainsi que la possibilité de définir le fuseau horaire et le système de calendrier.

Dates représentables

Tous les objets Temporal qui représentent une date de calendrier spécifique imposent une limite similaire à l'étendue des dates représentables, qui est de ±108 jours (inclus) à partir de l'époque Unix, ou la plage d'instants de -271821-04-20T00:00:00 à +275760-09-13T00:00:00. Il s'agit de la même plage que pour les dates valides. Plus précisément :

  • Temporal.Instant et Temporal.ZonedDateTime appliquent cette limite directement sur leur valeur epochNanoseconds.
  • Temporal.PlainDateTime interprète la date-heure dans le fuseau horaire UTC et exige qu'elle soit dans la plage ±(108 + 1) jours (exclus) à partir de l'époque Unix, donc sa plage valide est de -271821-04-19T00:00:00 à +275760-09-14T00:00:00, exclus. Cela permet de convertir n'importe quel ZonedDateTime en PlainDateTime quel que soit son décalage.
  • Temporal.PlainDate applique la même vérification que PlainDateTime au midi (12:00:00) de cette date, donc sa plage valide est de -271821-04-19 à +275760-09-13. Cela permet de convertir n'importe quel PlainDateTime en PlainDate quelle que soit son heure, et inversement.
  • Temporal.PlainYearMonth a la plage valide de -271821-04 à +275760-09. Cela permet de convertir n'importe quel PlainDate en PlainYearMonth quelle que soit sa date (sauf si le premier jour d'un mois non ISO tombe dans le mois ISO -271821-03).

Les objets Temporal refuseront de construire une instance représentant une date/heure au-delà de cette limite. Cela inclut :

  • L'utilisation du constructeur ou de la méthode statique from().
  • L'utilisation de la méthode with() pour mettre à jour les champs du calendrier.
  • L'utilisation de add(), subtract(), round(), ou toute autre méthode pour dériver de nouvelles instances.

Propriétés statiques

Temporal.Duration

Représente une différence entre deux points dans le temps, qui peut être utilisée dans l'arithmétique de date/heure. Elle est fondamentalement représentée comme une combinaison de valeurs d'années, mois, semaines, jours, heures, minutes, secondes, millisecondes, microsecondes et nanosecondes.

Temporal.Instant

Représente un point unique dans le temps, avec une précision à la nanoseconde. Elle est fondamentalement représentée comme le nombre de nanosecondes écoulées depuis l'époque Unix (minuit au début du 1er janvier 1970, UTC), sans aucun fuseau horaire ni système de calendrier.

Temporal.Now

Fournit des méthodes pour obtenir l'heure actuelle dans différents formats.

Temporal.PlainDate

Représente une date de calendrier (une date sans heure ni fuseau horaire) ; par exemple, un évènement sur un calendrier qui a lieu toute la journée, quel que soit le fuseau horaire. Elle est fondamentalement représentée comme une date de calendrier ISO 8601, avec les champs année, mois et jour, et un système de calendrier associé.

Temporal.PlainDateTime

Représente une date (date de calendrier) et une heure (heure murale) sans fuseau horaire. Elle est fondamentalement représentée comme une combinaison d'une date (avec un système de calendrier associé) et d'une heure.

Temporal.PlainMonthDay

Représente le mois et le jour d'une date de calendrier, sans année ni fuseau horaire ; par exemple, un évènement sur un calendrier qui revient chaque année et a lieu toute la journée. Elle est fondamentalement représentée comme une date de calendrier ISO 8601, avec les champs année, mois et jour, et un système de calendrier associé. L'année est utilisée pour lever l'ambiguïté du mois-jour dans les systèmes de calendrier non ISO.

Temporal.PlainTime

Représente une heure sans date ni fuseau horaire ; par exemple, un évènement récurrent qui a lieu à la même heure chaque jour. Elle est fondamentalement représentée comme une combinaison de valeurs d'heure, minute, seconde, milliseconde, microseconde et nanoseconde.

Temporal.PlainYearMonth

Représente l'année et le mois d'une date de calendrier, sans jour ni fuseau horaire ; par exemple, un évènement sur un calendrier qui a lieu tout le mois. Elle est fondamentalement représentée comme une date de calendrier ISO 8601, avec les champs année, mois et jour, et un système de calendrier associé. Le jour est utilisé pour lever l'ambiguïté de l'année-mois dans les systèmes de calendrier non ISO.

Temporal.ZonedDateTime

Représente une date et une heure avec un fuseau horaire. Elle est fondamentalement représentée comme une combinaison d'un instant, d'un fuseau horaire et d'un système de calendrier.

Temporal[Symbol.toStringTag]

La valeur initiale de la propriété [Symbol.toStringTag] est la chaîne de caractères "Temporal". Cette propriété est utilisée dans Object.prototype.toString().

Spécifications

Specification
Temporal
# sec-temporal-objects

Compatibilité des navigateurs

Voir aussi