Серверный рендеринг

При серверном рендеринге (SSR) работа с датами в JavaScript требует строгой предсказуемости: любое расхождение между серверным и клиентским временем приводит к гидрационным ошибкам, визуальным «скачкам» интерфейса и трудноуловимым дефектам отображения. Библиотека Day.js используется в SSR-средах как компактная альтернатива Moment.js, обеспечивая иммутабельную модель данных, детерминированное форматирование и минимальный размер бандла при сохранении расширяемости через плагины.


Среда выполнения на сервере и в браузере различается по нескольким критическим параметрам:

  • часовой пояс системы
  • доступность Intl API и его конфигурации
  • локальные настройки окружения
  • время выполнения запроса

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

Day.js по умолчанию не изменяет системное время и опирается на Date, что делает поведение предсказуемым при условии явного управления часовыми поясами через плагины.


Детектирование и контроль зоны времени

Для серверного рендеринга ключевым аспектом становится фиксация временной зоны.

Использование UTC как промежуточного формата снижает количество ошибок:

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

dayjs.extend(utc)

const now = dayjs().utc().format()

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

При необходимости отображения локального времени используется явная конвертация:

const timestamp = '2026-05-23T10:15:00Z'

const local = dayjs(timestamp).local().format('YYYY-MM-DD HH:mm')

Гидрация и согласованность состояния

Основная проблема SSR заключается в совпадении HTML, сгенерированного на сервере, с DOM, созданным на клиенте.

Любая операция, зависящая от текущего времени, потенциально нарушает согласованность:

dayjs().format('HH:mm')

Если сервер и клиент выполняют этот код в разные моменты, результат различается.

Для устранения расхождений используется один из следующих подходов:

Фиксация времени на сервере

const serverNow = dayjs().valueOf()

// передача клиенту
const clientTime = dayjs(serverNow).format('HH:mm')

Предварительное форматирование

const formatted = dayjs(timestamp).format('YYYY-MM-DD HH:mm')

Сервер передаёт уже готовую строку, исключая повторное вычисление на клиенте.


Иммутабельность и предсказуемость вычислений

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

const base = dayjs('2026-01-01')

const shifted = base.add(7, 'day')
const formatted = base.format('YYYY-MM-DD')

base остаётся неизменным, что критично для SSR, где повторное использование объектов между запросами может приводить к утечкам состояния при неправильной архитектуре.


Изоляция состояния между запросами

В серверных приложениях важно избегать глобальных экземпляров с изменяемым состоянием:

// потенциально опасно при неправильном использовании
const shared = dayjs()

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

function renderPage() {
  const now = dayjs()
  return now.format('YYYY-MM-DD')
}

Работа с плагинами в SSR

Day.js расширяется через плагины, каждый из которых должен быть зарегистрирован один раз в контексте процесса.

UTC и Local Time

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

Timezone

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

const tokyo = dayjs().tz('Asia/Tokyo')

Важно учитывать, что плагин timezone опирается на Intl и может вести себя по-разному в минимальных контейнерах или edge-окружениях.


Форматирование и детерминизм вывода

SSR требует строгой стабильности форматирования строк.

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

Любые локализованные форматы (.locale()) могут приводить к расхождениям, если сервер и клиент используют разные языковые настройки.

Пример фиксации локали:

import 'dayjs/locale/ru'

dayjs.locale('ru')

dayjs().format('D MMMM YYYY')

Избежание зависимостей от системного времени

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

В SSR предпочтительнее работать с переданными timestamp:

const createdAt = 1716451200000

const formatted = dayjs(createdAt).format('YYYY-MM-DD')

Это устраняет вариативность между запросами.


Кэширование результатов форматирования

В высоконагруженных SSR-системах форматирование дат может становиться затратной операцией при повторяющемся выводе одинаковых значений.

Применяется кэширование:

const cache = new Map()

function formatDate(ts) {
  if (cache.has(ts)) return cache.get(ts)

  const result = dayjs(ts).format('YYYY-MM-DD HH:mm')
  cache.set(ts, result)

  return result
}

Edge-окружения и ограничения Intl

В некоторых SSR-средах (serverless, edge runtime) доступность Intl.DateTimeFormat может быть ограничена или урезана.

Day.js в таких условиях сохраняет базовую функциональность, но локализованное форматирование может отличаться.

Режим UTC становится наиболее стабильной базой:

dayjs.utc(timestamp).format()

Совместимость с гидрацией React и Vue

При использовании React или Vue сервер формирует HTML, который затем «оживает» на клиенте.

Проблемные места:

  • dayjs() без фиксированного входа
  • использование format() с локалью
  • вычисление текущего времени внутри render-функции

Корректный подход:

function Component({ timestamp }) {
  const formatted = dayjs(timestamp).format('YYYY-MM-DD')
  return `<span>${formatted}</span>`
}

Производительность в SSR

Day.js оптимизирован под tree-shaking: подключаются только используемые плагины.

Минимальный вариант для SSR:

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

dayjs.extend(utc)

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


Обработка входных данных из API

API часто возвращают даты в разных форматах:

  • ISO 8601
  • UNIX timestamp (ms / s)
  • строки без таймзоны

Унификация выполняется на входе:

const normalized = dayjs(Number(apiDate))

или

const normalized = dayjs(apiDate).utc()

Нормализация на сервере снижает вероятность расхождений при рендеринге.


Безопасность и предсказуемость вычислений времени

SSR требует исключения побочных эффектов при вычислении дат:

  • отсутствие мутаций глобального состояния
  • запрет на скрытые зависимости от системного времени
  • фиксированные входные данные для форматирования

Day.js поддерживает этот подход за счёт функциональной модели API и отсутствия внутреннего состояния, зависящего от времени выполнения между вызовами.