Работа в режиме UTC

Модель времени UTC и её роль в JavaScript

Coordinated Universal Time (UTC) представляет собой универсальную шкалу времени, не зависящую от часовых поясов, переходов на летнее время и локальных настроек системы. В контексте веб-разработки UTC используется как базовый формат хранения и передачи времени между системами.

В JavaScript работа с датами в стандартном Date API фактически опирается на Unix-время (timestamp), но отображение и многие операции по умолчанию зависят от локальной временной зоны. Это приводит к необходимости явного управления UTC при разработке API, логирования, распределённых систем и интеграций.

Библиотека Day.js предоставляет модульную поддержку UTC через плагин utc, обеспечивая единообразную работу с датами без учёта локального смещения.


Подключение UTC-плагина

Работа в UTC-режиме в Day.js активируется через подключение расширения:

import dayjs from 'dayjs'
import utc from 'dayjs/plugin/utc'

dayjs.extend(utc)

После подключения становится доступен метод utc(), который переводит экземпляр Day.js в контекст UTC.

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


Создание даты в UTC-контексте

Создание объектов в UTC-режиме осуществляется несколькими способами.

Текущее время в UTC

dayjs.utc()

Возвращает текущий момент времени, интерпретированный в UTC.

Парсинг строки в UTC

dayjs.utc('2026-05-23T10:00:00Z')

Суффикс Z обозначает UTC-время в ISO-8601 формате. При его наличии смещение не применяется.

Парсинг локального времени как UTC

dayjs.utc('2026-05-23 10:00:00')

В этом случае строка интерпретируется как UTC-время напрямую, без пересчёта из локальной зоны.


Различие между локальным временем и UTC

Обычный экземпляр Day.js:

dayjs('2026-05-23 10:00:00')

интерпретирует строку как локальное время окружения.

UTC-экземпляр:

dayjs.utc('2026-05-23 10:00:00')

фиксирует значение как UTC без смещения.

Конвертация между режимами:

const local = dayjs()
const utcTime = dayjs.utc(local)

или обратное преобразование:

const backToLocal = utcTime.local()

Метод local() возвращает значение с учётом локальной временной зоны окружения выполнения.


Форматирование UTC-дат

Форматирование в Day.js не зависит от того, находится ли объект в UTC или локальном режиме, но влияет на итоговое значение.

dayjs.utc('2026-05-23T10:00:00Z').format()
// 2026-05-23T10:00:00Z (в зависимости от формата и плагинов)

Часто используется явное указание формата:

dayjs.utc().format('YYYY-MM-DD HH:mm:ss')

Результат всегда соответствует UTC-времени без локального смещения.


ISO-форматы и сериализация

Одной из ключевых операций является получение ISO-строки:

dayjs.utc().toISOString()

Результат всегда соответствует стандарту ISO-8601 и заканчивается Z, обозначающим UTC.

Сравнение:

  • dayjs().toISOString() — преобразует локальное время в UTC
  • dayjs.utc().toISOString() — уже находится в UTC-контексте

Это различие критично для API, где сервер ожидает строго нормализованное время.


Арифметика дат в UTC

Все операции добавления и вычитания времени выполняются без учёта локального смещения.

dayjs.utc('2026-05-23T10:00:00Z').add(1, 'day')
dayjs.utc('2026-05-23T10:00:00Z').subtract(2, 'hours')

При этом Day.js оперирует внутренним timestamp, поэтому арифметика остаётся консистентной независимо от режима.

Особенность проявляется при переходах через границы суток:

dayjs.utc('2026-01-31T23:00:00Z').add(2, 'hours')

Результат корректно переносится на следующий день без влияния локальных правил перехода на летнее время.


Начало и конец временных интервалов

UTC-режим влияет на вычисление границ периодов:

dayjs.utc('2026-05-23T10:00:00Z').startOf('day')
dayjs.utc('2026-05-23T10:00:00Z').endOf('day')

В UTC-контексте «день» всегда фиксирован от 00:00:00Z до 23:59:59.999Z, независимо от локальной зоны.

Это особенно важно для агрегации логов и аналитики.


Парсинг и нормализация входных данных

Входные данные часто поступают в смешанных форматах:

  • ISO-строки с Z
  • строки без часового пояса
  • timestamp (milliseconds)

Поведение:

dayjs.utc(1716451200000)

timestamp интерпретируется как абсолютное время и не зависит от локальной зоны.

dayjs.utc('2026-05-23T10:00:00')

строка без Z трактуется как UTC, что может отличаться от стандартного Date.

Для унификации используется правило: все входные данные нормализуются через utc().


Взаимодействие с timezone-плагином

UTC-плагин часто используется совместно с расширением timezone:

import timezone from 'dayjs/plugin/timezone'
dayjs.extend(timezone)

Сценарии:

dayjs.utc().tz('Europe/Berlin')
  • UTC задаёт базовую точку
  • timezone выполняет смещение под конкретную зону

Обратное преобразование:

dayjs.tz('2026-05-23 10:00:00', 'Europe/Berlin').utc()

Такой подход используется для хранения данных в UTC и отображения в локальных часовых поясах.


Особенности неизменяемости объектов

Каждый вызов метода возвращает новый экземпляр:

const a = dayjs.utc()
const b = a.add(1, 'day')

a остаётся неизменным. Это критично для предотвращения побочных эффектов в цепочках вычислений.


Типичные проблемы при работе с UTC

1. Неявная локальная интерпретация

dayjs('2026-05-23 10:00:00')

создаёт локальное время, что приводит к расхождениям при сериализации.

2. Двойная конвертация

dayjs.utc(dayjs.utc(date))

может приводить к логическим ошибкам при повторной нормализации.

3. DST-переходы

Локальные зоны с переходом на летнее время могут давать сдвиги:

dayjs('2026-03-29')

в локальном режиме может отличаться по фактическому смещению, тогда как UTC полностью игнорирует DST.

4. Потеря информации о зоне

После преобразования в UTC исходная временная зона не сохраняется, если не используется отдельное поле или timezone-плагин.


Практические сценарии применения UTC

Логирование событий

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

const log = {
  time: dayjs.utc().toISOString(),
  event: 'user_login'
}

API-ответы

return {
  createdAt: dayjs.utc(entity.createdAt).toISOString()
}

Планировщики задач

const runAt = dayjs.utc('2026-06-01T00:00:00Z')

UTC исключает неоднозначности при распределённых очередях задач.

Базы данных

Хранение timestamp в UTC предотвращает расхождения между серверами в разных регионах.


Стратегия использования UTC как базового режима

В архитектуре приложений часто применяется модель:

  • хранение — UTC
  • транспорт — UTC (ISO-8601)
  • отображение — локальное время (через .local() или timezone)

Day.js поддерживает этот подход за счёт явного разделения utc() и local() режимов, обеспечивая предсказуемую трансформацию временных данных.