Coordinamento di eventi globali con Temporal

Funzionalità web: Temporal

La pianificazione di eventi in fusi orari diversi è notoriamente difficile con l'oggetto Date precedente, in particolare durante le transizioni dell'ora legale, quando le ore possono essere saltate o ripetute.

L'API Temporal fornisce Temporal.ZonedDateTime per rappresentare una data e un'ora in un fuso orario specifico, gestendo le transizioni dell'ora legale in modo automatico e prevedibile.

Modalità di implementazione

Per coordinare gli eventi globali e gestire i potenziali conflitti relativi all'ora legale:

  1. OBBLIGATORIO: crea un ZonedDateTime: utilizza Temporal.ZonedDateTime.from() per creare un oggetto data-ora che tiene conto del fuso orario.
  2. OBBLIGATORIO: Gestisci ambiguità: utilizza l'opzione disambiguation per controllare il comportamento quando un orario è ambiguo o non esiste (ad esempio, durante i cambi di orario).
  3. MANDATORY: Convert Time Zones: Use .withTimeZone() to see the equivalent time in another location.

Esempio: pianificazione e rilevamento dei conflitti

// 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' })}`);

Implementazione strategica e best practice

  • SÌ: utilizza Temporal.ZonedDateTime per gli eventi legati a una posizione geografica specifica (ad esempio una riunione in una città specifica).
  • SÌ: utilizza disambiguation: 'reject' se devi rilevare e avvisare gli utenti di conflitti di pianificazione durante le transizioni dell'ora legale.
  • CONSIGLIATO: utilizza disambiguation: 'compatible' (impostazione predefinita) se vuoi che il sistema scelga automaticamente un orario ragionevole quando si verificano conflitti.
  • NON utilizzare Temporal.PlainDateTime per gli eventi globali, in quanto non contiene informazioni sul fuso orario e non può tenere conto delle modifiche dell'ora legale.
  • SÌ: utilizza .withTimeZone() per calcolare l'ora equivalente in altre località senza modificare l'oggetto originale (gli oggetti Temporal sono immutabili).
  • SÌ: utilizza la formattazione .toLocaleString() nativa (ad esempio { hour: 'numeric', minute: '2-digit' }) per la visualizzazione dell'ora rivolta agli utenti anziché i calcoli e la spaziatura manuali dell'ora.

Strategia di riserva

Fallback e supporto del browser per Temporal

Per i browser che non supportano ancora l'API Temporal nativa, utilizza il rilevamento delle funzionalità e carica dinamicamente temporal-polyfill (~15 kB min+gz).

Tieni presente che l'importazione di temporal-polyfill non assegna automaticamente l'oggetto Temporal all'ambito globale. Assegnalo esplicitamente se il tuo codice si basa su 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();
})();