Конвертация в UTC и обратно

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

UTC в контексте библиотеки реализуется через отдельный плагин utc, который расширяет базовый API и добавляет режим интерпретации даты как универсального времени.

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

dayjs.extend(utc)

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


Инициализация дат в UTC

Создание даты в UTC-режиме отличается от стандартного локального парсинга. При использовании dayjs.utc() входная строка интерпретируется как UTC-время, без смещения локальной зоны.

const d1 = dayjs.utc('2026-01-01T12:00:00Z')
const d2 = dayjs.utc('2026-01-01 12:00:00')

Во втором случае отсутствие суффикса Z не означает локальное время — строка всё равно трактуется как UTC.

Форматирование в ISO также возвращает значение с суффиксом Z:

d1.toISOString() // 2026-01-01T12:00:00.000Z

Конвертация локального времени в UTC

Любой локальный объект может быть переведён в UTC-режим через метод utc(). При этом сохраняется момент времени, но меняется его представление.

const local = dayjs('2026-01-01 15:00:00')

const asUtc = local.utc()

Внутренне происходит пересчёт с учётом системного часового пояса. Например, при UTC+6:

  • локальное 15:00
  • UTC будет 09:00

Форматирование подтверждает смещение:

asUtc.format() // 2026-01-01T09:00:00Z (примерно)

Обратная конвертация UTC → локальное время

Обратное преобразование выполняется через .local(). Оно переводит UTC-время в представление текущей системной зоны.

const utcTime = dayjs.utc('2026-01-01T09:00:00Z')

const localTime = utcTime.local()

В этом режиме происходит добавление смещения часового пояса среды выполнения.


Парсинг строк с явным UTC и без него

Различие между строками с Z и без него критично для корректной интерпретации.

dayjs('2026-01-01T12:00:00Z')   // UTC
dayjs('2026-01-01T12:00:00')    // локальное время

После подключения utc поведение становится более предсказуемым при явном использовании dayjs.utc().


Форматирование и контроль представления

Форматирование не изменяет внутреннего значения, но влияет на отображение.

const d = dayjs.utc('2026-01-01T12:00:00Z')

d.format('YYYY-MM-DD HH:mm')       // 2026-01-01 12:00
d.local().format('YYYY-MM-DD HH:mm') // зависит от зоны

Метод toISOString() всегда возвращает UTC:

d.toISOString()

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

Сравнение дат корректно только при одинаковой интерпретации. UTC-режим устраняет неоднозначность.

const a = dayjs.utc('2026-01-01T10:00:00Z')
const b = dayjs.utc('2026-01-01T12:00:00Z')

a.isBefore(b) // true

Если один объект локальный, а другой UTC, возможны ошибки сравнения из-за скрытых смещений.


Работа с таймзонами через UTC как базовый слой

Day.js не содержит полноценной поддержки IANA time zone без дополнительных плагинов, поэтому UTC часто используется как универсальный промежуточный формат.

Типичный подход:

  1. Хранение всех дат в UTC
  2. Перед отображением — перевод в локальное время
  3. При вводе данных — нормализация в UTC
const input = '2026-01-01 18:00:00'

const stored = dayjs(input).utc()
const display = stored.local().format('YYYY-MM-DD HH:mm')

Потеря и восстановление смещения

При переходах между utc() и local() важно учитывать, что сохраняется момент времени, а не исходное представление.

const original = dayjs('2026-01-01 12:00:00')

const utcVersion = original.utc()
const backToLocal = utcVersion.local()

Исходный текстовый формат теряется, но временная точка остаётся неизменной.


Работа с ISO-строками и API

Большинство серверных API используют ISO 8601 с UTC:

const payload = {
  createdAt: dayjs().utc().toISOString()
}

При получении данных:

const fromServer = dayjs.utc(apiResponse.createdAt)

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


DST и сезонные переходы

Переходы на летнее и зимнее время влияют только на локальное представление. UTC остаётся стабильным ориентиром.

const winter = dayjs('2026-01-01').utc()
const summer = dayjs('2026-07-01').utc()

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


Цепочки преобразований

Day.js поддерживает цепочки вызовов, где каждый шаг возвращает новый объект:

const result = dayjs('2026-01-01 10:00:00')
  .utc()
  .add(2, 'hour')
  .local()
  .format('YYYY-MM-DD HH:mm')

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


Частые источники ошибок при конвертации

Непоследовательное использование UTC и локального режима приводит к смещению времени:

dayjs('2026-01-01T10:00:00')   // локальное
dayjs.utc('2026-01-01T10:00:00') // UTC

Ещё один источник — двойная конвертация:

dayjs('2026-01-01').utc().local().utc()

Каждый переход сохраняет момент времени, но усложняет интерпретацию при отладке.


Нормализация времени перед хранением

Единый стандарт хранения — UTC-ISO строка:

function normalize(date) {
  return dayjs(date).utc().toISOString()
}

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