Coordonner des événements mondiaux avec Temporal

Fonctionnalités Web : Temporal

La planification d'événements dans différents fuseaux horaires est notoirement difficile avec l'ancien objet Date, en particulier lors des transitions vers l'heure d'été, lorsque des heures peuvent être ignorées ou répétées.

L'API Temporal fournit Temporal.ZonedDateTime pour représenter une date et une heure dans un fuseau horaire spécifique, en gérant les transitions d'heure d'été de manière automatique et prévisible.

Implémentation

Pour coordonner des événements mondiaux et gérer les conflits potentiels liés à l'heure d'été :

  1. OBLIGATOIRE : Créer un ZonedDateTime : utilisez Temporal.ZonedDateTime.from() pour créer un objet date-heure qui tient compte du fuseau horaire.
  2. OBLIGATOIRE : Gérer l'ambiguïté : utilisez l'option disambiguation pour contrôler le comportement lorsqu'une heure est ambiguë ou n'existe pas (par exemple, lors des changements d'heure).
  3. OBLIGATOIRE : Convertir les fuseaux horaires : utilisez .withTimeZone() pour voir l'heure équivalente dans un autre lieu.

Exemple : Planification et détection des conflits

// 1. Define the event time and target time zone
const date = "2025-03-09";
const time = "02:30"; // This time is skipped in New York during Spring Forward
const timeZone = "America/New_York";
const inputStr = `${date}T${time}[${timeZone}]`;

// 2. Detect conflicts using 'reject'
let hasConflict = false;
try {
  // 'reject' throws RangeError if the time is ambiguous or does not exist
  Temporal.ZonedDateTime.from(inputStr, { disambiguation: 'reject' });
} catch (e) {
  if (e instanceof RangeError) {
    hasConflict = true;
    console.log("This time falls in a DST transition gap or overlap.");
  }
}

// 3. Resolve the time safely using 'compatible' (default)
// 'compatible' will resolve to a valid time even if skipped or repeated
const hostTime = Temporal.ZonedDateTime.from(inputStr, { disambiguation: 'compatible' });
console.log(`Resolved time: ${hostTime.toString()}`);

// 4. Convert to another time zone (e.g., Tokyo)
const tokyoTime = hostTime.withTimeZone("Asia/Tokyo");
// Use toLocaleString() for user-facing display instead of manual hour/minute padding
console.log(`Tokyo time: ${tokyoTime.toLocaleString('en-US', { hour: 'numeric', minute: '2-digit' })}`);

Implémentation stratégique et bonnes pratiques

  • À FAIRE : Utilisez Temporal.ZonedDateTime pour les événements liés à un emplacement géographique spécifique (comme une réunion dans une ville spécifique).
  • À FAIRE : Utilisez disambiguation: 'reject' si vous devez détecter les conflits de planification lors des transitions vers l'heure d'été et en avertir les utilisateurs.
  • À FAIRE : Utilisez disambiguation: 'compatible' (valeur par défaut) lorsque vous souhaitez que le système choisisse automatiquement une heure appropriée en cas de conflit.
  • N'UTILISEZ PAS Temporal.PlainDateTime pour les événements mondiaux, car il ne contient pas d'informations sur le fuseau horaire et ne peut pas tenir compte des changements d'heure d'été.
  • À FAIRE : Utilisez .withTimeZone() pour calculer l'heure équivalente dans d'autres lieux sans modifier l'objet d'origine (les objets temporels sont immuables).
  • À FAIRE : Utilisez la mise en forme .toLocaleString() native (comme { hour: 'numeric', minute: '2-digit' }) pour les affichages de l'heure visibles par l'utilisateur, plutôt que des calculs et des remplissages manuels de l'heure.

Stratégie de remplacement

Solutions de remplacement et compatibilité des navigateurs avec Temporal

Pour les navigateurs qui ne sont pas encore compatibles avec l'API Temporal native, utilisez la détection de fonctionnalités et chargez dynamiquement temporal-polyfill (~15 Ko min+gz).

Notez que l'importation de temporal-polyfill n'attribue pas automatiquement l'objet Temporal au champ d'application global. Attribuez-la explicitement si votre code repose sur globalThis.Temporal.

// Check if Temporal is supported natively
(async () => {
  if (typeof Temporal === 'undefined') {
    // Load the polyfill conditionally
    const module = await import('https://esm.sh/temporal-polyfill');
    globalThis.Temporal = module.Temporal;
    // Extend Date.prototype if needed
    Date.prototype.toTemporalInstant = module.toTemporalInstant;
  }
  initializeApp();
})();