Планировать мероприятия в разных часовых поясах с помощью устаревшего объекта Date очень сложно, особенно в период перехода на летнее время, когда часы могут пропускаться или повторяться.
API Temporal предоставляет Temporal.ZonedDateTime для представления даты и времени в определенном часовом поясе, автоматически и предсказуемо обрабатывая переходы на летнее время.
Как реализовать
Чтобы координировать глобальные мероприятия и избегать возможных конфликтов, связанных с переходом на летнее время:
- ОБЯЗАТЕЛЬНО. Создайте ZonedDateTime. Используйте
Temporal.ZonedDateTime.from(), чтобы создать объект даты и времени с учетом часового пояса. - ОБЯЗАТЕЛЬНО. Обработка неоднозначности. Используйте параметр
disambiguation, чтобы управлять поведением, когда время неоднозначно или не существует (например, при переводе часов). - ОБЯЗАТЕЛЬНО. Преобразование часовых поясов. Используйте
.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();
})();