Другое

Как преобразовать диапазон дат в UTC с помощью JavaScript

Узнайте, как преобразовать локальные диапазоны дат в UTC с помощью JavaScript. Руководство с примерами конвертации часовых поясов и форматирования дат для серверной обработки.

Как преобразовать локальный диапазон дат в UTC с помощью JavaScript?
Предположим, пользователь вашего сайта вводит диапазон дат:

2009-1-1 to 2009-1-3

Нужно отправить эти даты на сервер для обработки, но сервер ожидает, что все даты и времена будут в UTC.
Если пользователь находится в Аляске (часовой пояс отличается от UTC), диапазон дат необходимо преобразовать в что‑то вроде:

2009-1-1T8:00:00 to 2009-1-4T7:59:59

С помощью объекта Date в JavaScript, как бы вы преобразовали первый «локальный» диапазон дат в формат UTC, который понимает сервер?

Чтобы преобразовать локализованный диапазон дат в UTC в JavaScript, необходимо создать объекты Date для начала и конца диапазона, применить коррекцию смещения часового пояса и отформатировать их как UTC‑таймстампы. Ключевым моментом является использование getTimezoneOffset() для определения разницы между локальным временем и UTC, а затем корректировка дат, чтобы сервер получил корректно преобразованные значения datetime в UTC.

Содержание

Понимание задачи

Когда пользователи вводят диапазоны дат без указания времени, обычно необходимо преобразовать их в диапазоны datetime в UTC для обработки на сервере. Проблема состоит в:

  1. Отсутствие информации о времени: Пользователи часто указывают только даты (например, «2009-1-1») без значений времени.
  2. Преобразование часового пояса: Конверсия должна учитывать смещение локального часового пояса пользователя.
  3. Границы диапазона: Необходимо корректно обрабатывать начало (начало дня) и конец (конец дня) диапазона.

Согласно Mozilla Developer Network, объект Date в JavaScript представляет один момент времени, поэтому важно понимать, как смещения часового пояса влияют на расчёты дат.

Базовые методы преобразования дат

Получение смещения часового пояса

Основной метод для преобразования часового пояса — getTimezoneOffset():

javascript
const currentTime = new Date();
const timezoneOffsetMinutes = currentTime.getTimezoneOffset();
const timezoneOffsetHours = timezoneOffsetMinutes / 60;

console.log(`UTC offset: ${timezoneOffsetHours} hours`);

Как объясняет CoreUI, этот метод возвращает разницу в минутах между UTC и локальным временем, что служит фундаментом для точных операций с датами, учитывающих часовой пояс.

Методы UTC

JavaScript предоставляет встроенные методы UTC для независимой от часового пояса работы с датами:

javascript
const date = new Date();
console.log(date.getFullYear()); // Локальный год
console.log(date.getUTCFullYear()); // UTC год
console.log(date.getMonth()); // Локальный месяц (0-11)
console.log(date.getUTCMonth()); // UTC месяц (0-11)

Преобразование диапазонов дат в UTC

Шаг 1: Создание объектов Date

Сначала распарсите ввод пользователя в объекты Date. Поскольку время не указано, предположим:

  • Начало диапазона: 00:00:00 (начало дня)
  • Конец диапазона: 23:59:59.999 (конец дня)
javascript
function parseDateRange(startDateStr, endDateStr) {
    // Парсим дату начала (начало дня)
    const startDate = new Date(startDateStr);
    startDate.setHours(0, 0, 0, 0);
    
    // Парсим дату окончания (конец дня)
    const endDate = new Date(endDateStr);
    endDate.setHours(23, 59, 59, 999);
    
    return { startDate, endDate };
}

Шаг 2: Коррекция смещения часового пояса

Преобразуйте локализованные даты в UTC, корректируя их на смещение часового пояса:

javascript
function convertToUTC(date) {
    const timezoneOffset = date.getTimezoneOffset(); // в минутах
    const utcDate = new Date(date.getTime() + timezoneOffset * 60000);
    return utcDate;
}

Шаг 3: Форматирование для сервера

Преобразуйте даты UTC в ISO‑формат или другой требуемый формат:

javascript
function formatDateForServer(date) {
    return date.toISOString(); // Возвращает формат вроде "2009-01-01T08:00:00.000Z"
}

Полный пример реализации

Ниже приведена полная реализация преобразования диапазона дат «2009-1-1 до 2009-1-3» в UTC:

javascript
function convertDateRangeToUTC(startDateStr, endDateStr) {
    // Парсим и задаём границы времени
    const startDate = new Date(startDateStr);
    startDate.setHours(0, 0, 0, 0);
    
    const endDate = new Date(endDateStr);
    endDate.setHours(23, 59, 59, 999);
    
    // Преобразуем в UTC
    const startUTC = new Date(startDate.getTime() + startDate.getTimezoneOffset() * 60000);
    const endUTC = new Date(endDate.getTime() + endDate.getTimezoneOffset() * 60000);
    
    // Форматируем для сервера
    return {
        start: startUTC.toISOString(),
        end: endUTC.toISOString()
    };
}

// Пример использования для часового пояса Аляски
const dateRange = convertDateRangeToUTC("2009-1-1", "2009-1-3");
console.log(dateRange.start); // "2009-01-01T08:00:00.000Z" (для Аляски)
console.log(dateRange.end);   // "2009-01-04T07:59:59.999Z" (для Аляски)

Расширенная версия с обнаружением часового пояса

Для более надёжной обработки можно определить часовой пояс пользователя:

javascript
function getUserTimezone() {
    return Intl.DateTimeFormat().resolvedOptions().timeZone;
}

function convertDateRangeWithTimezone(startDateStr, endDateStr, timezone = null) {
    const userTimezone = timezone || getUserTimezone();
    
    // Парсим даты с часовым поясом
    const startDate = new Date(startDateStr + "T00:00:00");
    const endDate = new Date(endDateStr + "T23:59:59");
    
    // Преобразуем в UTC
    const startUTC = new Date(startDate.getTime() + startDate.getTimezoneOffset() * 60000);
    const endUTC = new Date(endDate.getTime() + endDate.getTimezoneOffset() * 60000);
    
    return {
        timezone: userTimezone,
        start: startUTC.toISOString(),
        end: endUTC.toISOString()
    };
}

Альтернативные подходы

Использование библиотеки Date-fns

Для более надёжной работы с датами рассмотрите использование библиотеки, такой как date-fns:

javascript
import { utcToZonedTime, zonedTimeToUtc } from 'date-fns-tz';

function convertWithDateFns(startDateStr, endDateStr, timeZone) {
    const startDate = new Date(startDateStr + "T00:00:00");
    const endDate = new Date(endDateStr + "T23:59:59");
    
    const startUTC = zonedTimeToUtc(startDate, timeZone);
    const endUTC = zonedTimeToUtc(endDate, timeZone);
    
    return {
        start: startUTC.toISOString(),
        end: endUTC.toISOString()
    };
}

Использование библиотеки Luxon

Luxon предоставляет всестороннюю поддержку часовых поясов:

javascript
import { DateTime } from 'luxon';

function convertWithLuxon(startDateStr, endDateStr) {
    const start = DateTime.fromISO(startDateStr).set({ hour: 0, minute: 0, second: 0 });
    const end = DateTime.fromISO(endDateStr).set({ hour: 23, minute: 59, second: 59 });
    
    return {
        start: start.toUTC().toISO(),
        end: end.toUTC().toISO()
    };
}

Учет серверной обработки

Согласно документации PostgreSQL, при выводе значения типа timestamp with time zone всегда выполняется преобразование из UTC в текущий часовой пояс. Это означает, что ваш сервер может обрабатывать окончательное преобразование часового пояса, поэтому вы можете отправлять строки UTC‑таймстампов и позволить серверу обработать их соответствующим образом.

Заключение

  • Основной метод: используйте getTimezoneOffset() для получения разницы между локальным временем и UTC, затем корректируйте объекты Date соответственно.
  • Границы дат: всегда указывайте диапазон времени (начало в 00:00:00, конец в 23:59:59.999), когда пользователи вводят только даты.
  • Форматирование: используйте toISOString() для преобразования дат UTC в ISO‑формат при передаче на сервер.
  • Библиотеки: рассмотрите использование date-fns или Luxon для более сложных операций с часовыми поясами.
  • Тестирование: всегда проверяйте работу с разными часовыми поясами, чтобы убедиться, что логика преобразования работает корректно.

Для продакшн‑приложений рекомендуется использовать проверенные библиотеки, такие как date-fns-tz или Luxon, которые обеспечивают надёжную обработку часовых поясов и избегают крайних случаев, которые могут возникнуть при ручных расчётах смещения.

Источники

  1. CoreUI - Как получить смещение часового пояса в JavaScript
  2. Mozilla Developer Network - Документация по Date
  3. Документация PostgreSQL - Типы даты/времени
  4. Документация date-fns-tz
  5. Документация Luxon
Авторы
Проверено модерацией
Модерация