formatRelative для контекстного отображения

Назначение функции formatRelative

Функция formatRelative предназначена для отображения дат в человекочитаемом виде с учётом контекста между двумя моментами времени. В отличие от абсолютного форматирования (format) и чисто разностного (formatDistance), здесь используется сравнительная логика: дата интерпретируется относительно базовой точки отсчёта.

Основная идея заключается в том, что одна и та же дата может отображаться по-разному в зависимости от того, к какому моменту она привязана.

Например:

  • «вчера в 14:00»
  • «сегодня в 09:00»
  • «в следующую среду в 18:00»

Сигнатура и базовая структура

Функция имеет следующую сигнатуру:

formatRelative(date, baseDate, [options])
  • date — дата, которую необходимо отобразить
  • baseDate — точка отсчёта (контекстная дата)
  • options — дополнительные настройки (локализация и форматирование)

Возвращаемое значение — строка с локализованным представлением даты относительно baseDate.


Принцип работы контекстного форматирования

Контекстное форматирование строится на сравнении двух временных точек:

  1. Сравнение по дню (сегодня, вчера, завтра, другой день недели)
  2. Сравнение по неделям (текущая неделя, следующая, прошлая)
  3. Сравнение по времени суток
  4. Выбор шаблона строки из локали

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


Локализация и роль шаблонов

Вся логика formatRelative зависит от объекта locale. Внутри каждой локали определены шаблоны для разных сценариев:

  • сегодня
  • вчера
  • завтра
  • в пределах недели
  • вне недели

Пример структуры локали:

const locale = {
  formatRelative: (token, date, baseDate, options) => {
    return mapping[token];
  }
}

На практике используется готовая локаль, например enUS, ru, de.


Основные токены formatRelative

Функция использует внутренние токены, которые определяют тип относительности:

  • lastWeek
  • yesterday
  • today
  • tomorrow
  • nextWeek
  • other

Каждый токен соответствует конкретному шаблону строки.

Пример:

  • today → “сегодня в p”
  • yesterday → “вчера в p”
  • nextWeek → “в следующую EEEE в p”

Поведение относительно baseDate

Ключевой параметр — baseDate. Именно он определяет контекст:

import { formatRelative } from 'date-fns'

formatRelative(new Date(2026, 4, 22, 15, 0), new Date(2026, 4, 21))

Здесь результат будет зависеть от того, попадает ли дата в диапазон «сегодня», «вчера» или «завтра» относительно baseDate.

Сдвиг baseDate меняет всю интерпретацию результата без изменения самой даты.


Пример базового использования

import { formatRelative } from 'date-fns'

const date = new Date(2026, 4, 22, 18, 30)
const base = new Date(2026, 4, 21, 12, 0)

formatRelative(date, base)
// "завтра в 18:30"

При изменении base результат может стать другим:

const base = new Date(2026, 4, 20, 12, 0)

formatRelative(date, base)
// "через 2 дня в 18:30"

Отличие от formatDistance

formatDistance возвращает числовую разницу:

  • «2 дня»
  • «3 часа»

formatRelative добавляет контекст:

  • «вчера в 14:00»
  • «на прошлой неделе в 09:00»

Разница принципиальная:

Функция Результат Характер
formatDistance 2 дня количественный
formatRelative вчера контекстный

Отличие от format

format полностью игнорирует контекст:

format(date, 'yyyy-MM-dd HH:mm')

Результат всегда одинаковый.

formatRelative динамически меняет строку в зависимости от baseDate.


Использование локали ru

При подключении русской локали поведение становится значительно богаче:

import { formatRelative } from 'date-fns'
import { ru } from 'date-fns/locale'

formatRelative(date, base, { locale: ru })

В русской локализации используются естественные конструкции:

  • «вчера в…»
  • «сегодня в…»
  • «завтра в…»
  • «в следующую среду в…»

Форматирование времени внутри шаблонов

Внутри строк локали используется токен p, который подставляет локализованное время.

Примеры:

  • today at p
  • yesterday at p
  • nextWeek on EEEE at p

Где:

  • p — локализованное время
  • EEEE — день недели полностью

Поведение при переходе границ недели

Одним из сложных моментов является переход между неделями.

Если дата попадает:

  • в текущую неделю → используется today / yesterday
  • в следующую неделю → используется nextWeek
  • в прошлую → lastWeek

Это зависит от локали и настроек начала недели.


Начало недели и влияние локали

Некоторые локали используют понедельник как начало недели, другие — воскресенье.

Это влияет на классификацию:

  • дата может считаться «на прошлой неделе» или «вчерашней неделей» в зависимости от правил локали

Таким образом, formatRelative не является чисто математической функцией — он зависит от культурного контекста.


Сценарии применения

Чаты и мессенджеры

"сегодня в 12:45"
"вчера в 18:20"
"в понедельник в 09:00"

Контекст делает интерфейс естественным без лишних вычислений.


Ленты активности

  • «2 часа назад» заменяется на «сегодня в 14:00»
  • «вчера» вместо точной даты

Логи событий

Позволяет сгруппировать события по времени без потери точности.


Граничные случаи

Разные дни при одинаковом времени

date: 22 мая 18:00
base: 22 мая 23:00

Результат может быть «сегодня в 18:00», несмотря на то что разница отрицательная.


Переход через полночь

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


Таймзоны

formatRelative работает с объектами Date, поэтому таймзона уже должна быть учтена до вызова функции. Иначе возможны некорректные «сегодня/вчера».


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

При массовом форматировании (например, списки сообщений) важно учитывать:

  • локаль создаёт дополнительную нагрузку
  • лучше переиспользовать один и тот же locale объект
  • избегать пересоздания Date

Сравнение с ручной реализацией

Ручная реализация обычно включает:

  • вычисление разницы дней
  • проверку диапазонов
  • форматирование строки

formatRelative заменяет всю эту логику одной функцией, но требует доверия к локали.


Типичные ошибки использования

  • использование без baseDate
  • игнорирование локали
  • ожидание абсолютной точности времени
  • попытка использовать как замену formatDistance

Поведение при null и некорректных датах

При некорректных входных данных функция возвращает Invalid Date, если используется некорректный Date объект.


Итоговая модель работы

formatRelative можно рассматривать как слой над тремя механизмами:

  1. сравнение дат
  2. выбор категории относительности
  3. применение локализованного шаблона

Эта комбинация позволяет создавать интерфейсы, где время воспринимается естественно и без избыточной точности.