Français

Un guide complet sur l'utilisation de l'API Temporal de JavaScript pour des calculs d'intervalles de temps précis et intuitifs, de la création de durées de base à l'arithmétique avancée et au formatage.

Durée Temporal en JavaScript : Maîtriser les Calculs d'Intervalles de Temps

L'API Temporal de JavaScript introduit une manière moderne et puissante de gérer les dates, les heures et les intervalles de temps. L'objet Temporal.Duration représente une durée, offrant une approche claire et intuitive pour effectuer des calculs avec des intervalles de temps. Cet article explore en détail Temporal.Duration, montrant comment créer, manipuler et formater des durées pour divers cas d'utilisation.

Qu'est-ce que Temporal.Duration ?

Temporal.Duration représente un laps de temps, l'exprimant en termes d'années, de mois, de jours, d'heures, de minutes, de secondes et de fractions de seconde (millisecondes, microsecondes, nanosecondes). Contrairement aux objets Date qui représentent un point spécifique dans le temps, Temporal.Duration représente une quantité de temps. Il respecte le format de durée ISO 8601 (par exemple, P1Y2M10DT2H30M représente 1 an, 2 mois, 10 jours, 2 heures et 30 minutes). L'API Temporal est conçue pour être plus intuitive et moins sujette aux erreurs que l'ancien objet Date.

Créer des Objets Temporal.Duration

Il existe plusieurs manières de créer des objets Temporal.Duration :

1. À partir d'un objet simple

Vous pouvez créer une durée en passant un objet avec les propriétés souhaitées :

const duration = new Temporal.Duration(1, 2, 10, 2, 30, 0, 0, 0);
console.log(duration.toString()); // Sortie : P1Y2M10DT2H30M

Cela crée une durée de 1 an, 2 mois, 10 jours, 2 heures et 30 minutes. Notez que les arguments correspondent à l'ordre suivant : years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds.

2. À partir d'une chaîne ISO 8601

Vous pouvez également créer une durée à partir d'une chaîne de durée ISO 8601 en utilisant Temporal.Duration.from() :

const duration = Temporal.Duration.from("P1Y2M10DT2H30M");
console.log(duration.toString()); // Sortie : P1Y2M10DT2H30M

Ceci est particulièrement utile lorsque vous traitez des durées stockées sous forme de chaîne de caractères ou reçues d'une source externe.

3. En utilisant les méthodes add() et subtract() avec Temporal.Instant, Temporal.ZonedDateTime, etc.

Lorsque vous ajoutez ou soustrayez Temporal.Duration d'autres types Temporal (comme Temporal.Instant ou Temporal.ZonedDateTime), une Temporal.Duration est retournée représentant la différence entre les deux points dans le temps si vous les soustrayez ensuite. Par exemple :

const now = Temporal.Now.zonedDateTimeISO();
const later = now.add({ hours: 5 });
const duration = later.since(now);
console.log(duration.toString()); // Sortie : PT5H

Accéder aux Composants d'une Durée

Vous pouvez accéder aux composants individuels d'un objet Temporal.Duration en utilisant ses propriétés :

const duration = Temporal.Duration.from("P1Y2M10DT2H30M");
console.log(duration.years);      // Sortie : 1
console.log(duration.months);     // Sortie : 2
console.log(duration.days);       // Sortie : 10
console.log(duration.hours);      // Sortie : 2
console.log(duration.minutes);     // Sortie : 30
console.log(duration.seconds);     // Sortie : 0
console.log(duration.milliseconds); // Sortie : 0
console.log(duration.microseconds); // Sortie : 0
console.log(duration.nanoseconds);  // Sortie : 0

Effectuer des Opérations Arithmétiques avec les Durées

Les objets Temporal.Duration prennent en charge l'addition et la soustraction via les méthodes add() et subtract(). Ces méthodes retournent un nouvel objet Temporal.Duration représentant le résultat de l'opération.

const duration1 = Temporal.Duration.from("P1Y2M");
const duration2 = Temporal.Duration.from("P3M4D");

const addedDuration = duration1.add(duration2);
console.log(addedDuration.toString()); // Sortie : P1Y5M4D

const subtractedDuration = duration1.subtract(duration2);
console.log(subtractedDuration.toString()); // Sortie : P10M26D

Vous pouvez également enchaîner ces méthodes pour des calculs plus complexes :

const duration = Temporal.Duration.from("P1D").add({ hours: 12 }).subtract({ minutes: 30 });
console.log(duration.toString()); // Sortie : P1DT11H30M

La méthode negated() retourne un nouvel objet Temporal.Duration avec tous les composants inversés (négatifs) :

const duration = Temporal.Duration.from("P1Y2M10DT2H30M");
const negatedDuration = duration.negated();
console.log(negatedDuration.toString()); // Sortie : -P1Y2M10DT2H30M

La méthode abs() retourne un nouvel objet Temporal.Duration avec tous les composants en valeurs positives (valeurs absolues) :

const duration = Temporal.Duration.from("-P1Y2M10DT2H30M");
const absoluteDuration = duration.abs();
console.log(absoluteDuration.toString()); // Sortie : P1Y2M10DT2H30M

La méthode with() vous permet de créer une nouvelle instance de Temporal.Duration avec certaines, ou toutes, les propriétés modifiées avec de nouvelles valeurs. Si une valeur n'est pas spécifiée dans l'objet d'argument, la valeur originale de la durée sera utilisée. Par exemple :

const duration = Temporal.Duration.from("P1Y2M10DT2H30M");
const newDuration = duration.with({ years: 2, days: 5 });
console.log(newDuration.toString()); // Sortie : P2Y2M5DT2H30M

Normaliser les Durées

Les durées peuvent parfois être exprimées sous une forme non normalisée (par exemple, P1Y12M, qui pourrait être simplifié en P2Y). La méthode normalized() tente de simplifier une durée à sa forme la plus compacte. Cependant, elle nécessite une date de référence pour gérer les complexités des longueurs de mois variables. Pour normaliser correctement, vous aurez besoin d'une instance de Temporal.PlainDate, Temporal.ZonedDateTime ou Temporal.Instant.

Par exemple, la normalisation d'une durée impliquant des mois et des jours nécessite une date de référence :

const duration = Temporal.Duration.from("P1M32D");
const referenceDate = Temporal.PlainDate.from("2024-01-01");
const normalizedDuration = duration.normalized({ relativeTo: referenceDate });
console.log(normalizedDuration.toString()); // Sortie : P2M1D

Dans cet exemple, la durée P1M32D est normalisée par rapport au 1er janvier 2024, ce qui donne P2M1D car janvier a 31 jours.

Si vous ne traitez que des composantes de temps (heures, minutes, secondes, etc.), vous pouvez normaliser sans date de référence :

const duration = Temporal.Duration.from("PT25H61M");
const normalizedDuration = duration.normalized({ relativeTo: null }); //ou omettre l'argument relativeTo
console.log(normalizedDuration.toString()); // Sortie : P1DT2H1M

Comparer les Durées

Vous pouvez comparer des durées en utilisant la méthode compare(). Cette méthode retourne :

const duration1 = Temporal.Duration.from("P1Y");
const duration2 = Temporal.Duration.from("P6M");

const comparisonResult = Temporal.Duration.compare(duration1, duration2);
console.log(comparisonResult); // Sortie : 1

Exemples Pratiques

1. Calculer le Temps Restant Avant un Événement

Supposons que vous souhaitiez calculer le temps restant avant un événement spécifique. Utilisez Temporal.Now.zonedDateTimeISO() pour obtenir l'heure actuelle, et soustrayez la date de l'événement. Si la date de l'événement est passée, le résultat sera négatif.

const eventDate = Temporal.ZonedDateTime.from({ timeZone: 'America/Los_Angeles', year: 2024, month: 12, day: 25, hour: 9, minute: 0, second: 0 });
const now = Temporal.Now.zonedDateTimeISO('America/Los_Angeles');

const durationUntilEvent = eventDate.since(now);

console.log(durationUntilEvent.toString()); // Sortie : ex., P262DT14H30M (selon la date et l'heure actuelles)

2. Suivre la Durée des Tâches d'un Projet

En gestion de projet, vous pouvez utiliser Temporal.Duration pour suivre la durée estimée ou réelle des tâches.

const task1EstimatedDuration = Temporal.Duration.from("PT8H"); // 8 heures
const task2EstimatedDuration = Temporal.Duration.from("PT16H"); // 16 heures

const totalEstimatedDuration = task1EstimatedDuration.add(task2EstimatedDuration);
console.log(`Durée totale estimée : ${totalEstimatedDuration.toString()}`); // Sortie : Durée totale estimée : P1DT

3. Calculer l'Âge

Bien que le calcul précis de l'âge nécessite de prendre en compte les années bissextiles et les fuseaux horaires, Temporal.Duration peut fournir une estimation raisonnable :

const birthDate = Temporal.PlainDate.from("1990-05-15");
const currentDate = Temporal.PlainDate.from("2024-01-20");

const ageDuration = currentDate.since(birthDate, { smallestUnit: 'years' });
console.log(`Âge estimé : ${ageDuration.years} ans`); // Sortie : Âge estimé : 33 ans

4. Afficher des Durées Lisibles par l'Homme

Souvent, vous devez afficher les durées dans un format lisible par l'homme. Bien que Temporal.Duration n'ait pas de fonctions de formatage intégrées, vous pouvez créer une logique de formatage personnalisée :

function formatDuration(duration) {
  const parts = [];
  if (duration.years) parts.push(`${duration.years} an${duration.years > 1 ? 's' : ''}`);
  if (duration.months) parts.push(`${duration.months} mois`);
  if (duration.days) parts.push(`${duration.days} jour${duration.days > 1 ? 's' : ''}`);
  if (duration.hours) parts.push(`${duration.hours} heure${duration.hours > 1 ? 's' : ''}`);
  if (duration.minutes) parts.push(`${duration.minutes} minute${duration.minutes > 1 ? 's' : ''}`);
  if (duration.seconds) parts.push(`${duration.seconds} seconde${duration.seconds > 1 ? 's' : ''}`);

  return parts.join(', ');
}

const duration = Temporal.Duration.from("P1Y2M10DT2H30M");
const formattedDuration = formatDuration(duration);
console.log(formattedDuration); // Sortie : 1 an, 2 mois, 10 jours, 2 heures, 30 minutes

Utilisation Avancée et Considérations

1. Gestion des Fuseaux Horaires

Lorsque vous traitez des intervalles de temps qui franchissent des frontières de fuseaux horaires ou des changements d'heure d'été, il est crucial d'utiliser Temporal.ZonedDateTime pour garantir des calculs précis. L'utilisation de Temporal.PlainDate et Temporal.PlainTime évitera toute conversion de fuseau horaire.

2. Plus Petite Unité et Arrondi

Les méthodes `since()` et `until()` acceptent souvent des options pour définir la plus petite unité pour la durée résultante. Par exemple, pour calculer le temps *jusqu'à* un événement et limiter les résultats aux jours.

const eventDate = Temporal.PlainDate.from("2024-12-25");
const now = Temporal.PlainDate.from("2024-01-20");

const durationUntilEvent = now.until(eventDate, { smallestUnit: 'days' });

console.log(durationUntilEvent.toString()); //exemple de sortie PT340D

3. Secondes Intercalaires

Temporal ne prend pas en charge nativement les secondes intercalaires. Si vous avez besoin d'une précision extrême, vous devrez gérer les secondes intercalaires séparément.

4. Fuseaux Horaires IANA

L'API Temporal s'appuie sur la base de données des fuseaux horaires de l'IANA (Internet Assigned Numbers Authority). Assurez-vous que votre environnement dispose d'une version à jour de la base de données IANA pour gérer correctement les conversions de fuseaux horaires.

Bonnes Pratiques

Pièges Courants

Cas d'Utilisation Concrets à Travers Différentes Cultures

L'API Temporal peut être particulièrement bénéfique dans les applications mondiales où les différences de fuseaux horaires et les nuances culturelles sont importantes. Voici quelques exemples :

Conclusion

Temporal.Duration offre un moyen robuste et intuitif de travailler avec des intervalles de temps en JavaScript. En comprenant ses fonctionnalités et les bonnes pratiques, vous pouvez effectuer en toute confiance des calculs de durée précis et fiables dans vos applications. Adopter l'API Temporal conduit à un code plus propre, plus maintenable et réduit le risque d'erreurs associées à l'ancienne gestion des dates et des heures.

Au fur et à mesure que vous approfondissez l'API Temporal, n'oubliez pas de consulter la documentation officielle et d'expérimenter différents scénarios pour bien saisir ses capacités. Avec son design moderne et ses fonctionnalités complètes, Temporal est destiné à révolutionner la façon dont nous gérons les dates, les heures et les durées en JavaScript.