Настройка текстов календаря

Плагин calendar в Day.js отвечает за формирование человеко-читаемых текстов относительных дат, таких как «сегодня в 14:00», «вчера в 18:30» или «на прошлой неделе». Именно он определяет, как библиотека будет описывать дату в зависимости от её удалённости от текущего момента.

Функциональность календаря в Day.js основана на наборе правил, которые сопоставляют конкретный диапазон дат с текстовым шаблоном. Эти правила применяются при вызове метода:

dayjs().calendar()

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

dayjs().calendar(referenceDate)

Внутренне Day.js сравнивает текущую дату с опорной и выбирает одно из заранее определённых правил.

Основные категории сравнения:

  • текущий день
  • следующий день
  • предыдущий день
  • текущая неделя
  • предыдущая неделя
  • все остальные случаи

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

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

import dayjs from 'dayjs'
import calendar from 'dayjs/plugin/calendar'

dayjs.extend(calendar)

Без активации плагина метод calendar() недоступен.

Базовая структура правил форматирования

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

  • sameDay
  • nextDay
  • nextWeek
  • lastDay
  • lastWeek
  • sameElse

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

Пример базовой структуры:

import dayjs from 'dayjs'

dayjs.updateLocale('en', {
  calendar: {
    sameDay: '[Today at] HH:mm',
    nextDay: '[Tomorrow at] HH:mm',
    nextWeek: 'dddd [at] HH:mm',
    lastDay: '[Yesterday at] HH:mm',
    lastWeek: '[Last] dddd [at] HH:mm',
    sameElse: 'DD/MM/YYYY'
  }
})

Синтаксис шаблонов

В строковых шаблонах используются квадратные скобки для фиксации текста:

'[Today at]'

Все выражения внутри [] выводятся буквально без форматирования.

Оставшаяся часть строки интерпретируется как формат даты:

  • HH:mm — часы и минуты
  • dddd — полное название дня недели
  • DD/MM/YYYY — дата в числовом формате

Использование функций вместо строк

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

dayjs.updateLocale('en', {
  calendar: {
    sameDay: (now) => `[Today at] ${now.format('HH:mm')}`,
    nextDay: (now) => `[Tomorrow at] ${now.format('HH:mm')}`,
    lastDay: (now) => `[Yesterday at] ${now.format('HH:mm')}`,
    nextWeek: (now) => `${now.format('dddd')} [at] ${now.format('HH:mm')}`,
    lastWeek: (now) => `[Last] ${now.format('dddd')} [at] ${now.format('HH:mm')}`,
    sameElse: (now) => now.format('DD/MM/YYYY')
  }
})

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

Логика выбора шаблона

Day.js определяет категорию даты по следующим правилам:

sameDay

Используется, если дата совпадает с текущим днём.

sameDay: '[Today at] HH:mm'

nextDay

Используется для следующего календарного дня.

nextDay: '[Tomorrow at] HH:mm'

lastDay

Используется для предыдущего календарного дня.

lastDay: '[Yesterday at] HH:mm'

nextWeek

Применяется к датам, которые попадают в следующую неделю, но не являются «завтра».

nextWeek: 'dddd [at] HH:mm'

lastWeek

Применяется к датам из предыдущей недели.

lastWeek: '[Last] dddd [at] HH:mm'

sameElse

Фолбэк-правило для всех остальных случаев.

sameElse: 'DD.MM.YYYY'

Изменение локали календаря

Настройки календаря привязаны к конкретной локали. Для изменения используется updateLocale:

dayjs.updateLocale('ru', {
  calendar: {
    sameDay: '[Сегодня в] HH:mm',
    nextDay: '[Завтра в] HH:mm',
    lastDay: '[Вчера в] HH:mm',
    nextWeek: 'dddd [в] HH:mm',
    lastWeek: '[Прошлый] dddd [в] HH:mm',
    sameElse: 'DD.MM.YYYY'
  }
})

После этого все вызовы календаря для данной локали будут использовать новые строки.

Переключение локали и влияние на calendar

При смене локали автоматически подхватываются её правила:

import 'dayjs/locale/ru'

dayjs.locale('ru')

Если локаль содержит секцию calendar, она будет применена без дополнительных действий.

Передача опорной даты

Метод calendar может принимать вторым аргументом дату сравнения:

dayjs(date).calendar(referenceDate)

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

Пример:

const now = dayjs('2026-05-22 12:00')

dayjs('2026-05-21 18:00').calendar(now)

Результат будет зависеть от правил lastDay.

Использование с форматированием времени

Calendar-формат часто комбинируется с локализацией времени:

dayjs.updateLocale('ru', {
  calendar: {
    sameDay: '[Сегодня в] LT',
    nextDay: '[Завтра в] LT',
    lastDay: '[Вчера в] LT',
    nextWeek: 'dddd [в] LT',
    lastWeek: '[Прошлая] dddd [в] LT',
    sameElse: 'DD.MM.YYYY'
  }
})

LT — локализованный формат времени, который адаптируется под текущую локаль.

Приоритет правил и порядок обработки

Выбор шаблона происходит последовательно:

  1. Проверка совпадения с текущим днём
  2. Проверка завтра/вчера
  3. Проверка попадания в текущую или соседнюю неделю
  4. Использование fallback (sameElse)

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

Частые ошибки при настройке

Потеря квадратных скобок

Без скобок текст будет интерпретирован как формат:

sameDay: 'Today at HH:mm'

Результат может быть некорректным. Правильно:

sameDay: '[Today at] HH:mm'

Несовместимость с локалью

Если локаль не активирована, настройки календаря могут не применяться:

dayjs.locale('ru')

без подключения dayjs/locale/ru.

Перезапись без updateLocale

Прямое изменение объекта локали не применяется корректно:

// неправильно
dayjs.Ls.en.calendar = {}

Правильный способ:

dayjs.updateLocale('en', { calendar: {} })

Расширенные сценарии кастомизации

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

Пример адаптивного поведения:

dayjs.updateLocale('en', {
  calendar: {
    sameDay: (d) => {
      const hour = d.hour()
      return hour < 12
        ? `[Morning at] ${d.format('HH:mm')}`
        : `[Evening at] ${d.format('HH:mm')}`
    },
    nextDay: '[Tomorrow at] HH:mm',
    lastDay: '[Yesterday at] HH:mm',
    nextWeek: 'dddd [at] HH:mm',
    lastWeek: '[Last] dddd [at] HH:mm',
    sameElse: 'DD MMM YYYY'
  }
})

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