Координация глобальных событий с помощью Temporal

Веб-функции: Temporal

Планировать мероприятия в разных часовых поясах с помощью устаревшего объекта Date очень сложно, особенно в период перехода на летнее время, когда часы могут пропускаться или повторяться.

API Temporal предоставляет Temporal.ZonedDateTime для представления даты и времени в определенном часовом поясе, автоматически и предсказуемо обрабатывая переходы на летнее время.

Как реализовать

Чтобы координировать глобальные мероприятия и избегать возможных конфликтов, связанных с переходом на летнее время:

  1. ОБЯЗАТЕЛЬНО. Создайте ZonedDateTime. Используйте Temporal.ZonedDateTime.from(), чтобы создать объект даты и времени с учетом часового пояса.
  2. ОБЯЗАТЕЛЬНО. Обработка неоднозначности. Используйте параметр disambiguation, чтобы управлять поведением, когда время неоднозначно или не существует (например, при переводе часов).
  3. ОБЯЗАТЕЛЬНО. Преобразование часовых поясов. Используйте .withTimeZone(), чтобы узнать время в другом месте.

Пример: планирование и обнаружение конфликтов

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

Стратегическое внедрение и рекомендации

  • РЕКОМЕНДУЕТСЯ использовать Temporal.ZonedDateTime для мероприятий, привязанных к определенному географическому местоположению (например, для встречи в определенном городе).
  • РЕКОМЕНДУЕТСЯ использовать disambiguation: 'reject', если вам нужно обнаруживать конфликты в расписании во время перехода на летнее время и предупреждать о них пользователей.
  • РЕКОМЕНДУЕТСЯ использовать значение disambiguation: 'compatible' (по умолчанию), если вы хотите, чтобы система автоматически выбирала подходящее время при возникновении конфликтов.
  • НЕ ИСПОЛЬЗУЙТЕ Temporal.PlainDateTime для глобальных событий, поскольку в этом формате нет информации о часовом поясе и не учитывается переход на летнее время.
  • РЕКОМЕНДУЕТСЯ использовать .withTimeZone(), чтобы рассчитать эквивалентное время в других местоположениях, не изменяя исходный объект (объекты Temporal неизменяемы).
  • РЕКОМЕНДУЕТСЯ использовать встроенное форматирование .toLocaleString() (например, { hour: 'numeric', minute: '2-digit' }) для отображения времени пользователям вместо ручных вычислений и заполнения.

Резервная стратегия

Резервные варианты и поддержка Temporal в браузерах

Для браузеров, которые пока не поддерживают нативный API Temporal, используйте обнаружение функций и динамически загружайте temporal-polyfill (около 15 КБ min+gz).

Обратите внимание, что импорт temporal-polyfill не приводит к автоматическому назначению объекта Temporal глобальной области видимости. Если ваш код зависит от 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();
})();