Календарное представление дат

Календарное представление дат в Day.js реализуется через механизм форматирования, при котором дата отображается не как абсолютное значение (например, 2026-05-22 14:30), а как контекстное выражение относительно текущего момента: «сегодня в 14:30», «вчера в 18:00», «на прошлой неделе», «в следующий понедельник». Такой подход повышает читаемость временных меток в пользовательских интерфейсах и широко применяется в лентах событий, чатах, уведомлениях и логах активности.

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


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

Day.js не включает календарное представление по умолчанию, поэтому требуется явная активация расширения.

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

dayjs.extend(calendar)

После подключения становится доступен метод .calendar().


Базовое использование метода calendar()

Метод .calendar() преобразует дату в человекочитаемую строку относительно текущего момента времени.

dayjs().calendar()

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

  • «Today at 2:00 PM»
  • «Yesterday at 5:30 PM»
  • «Last Monday at 9:00 AM»
  • «05/10/2026»

Поведение зависит от локали и внутренних правил форматирования.

Передача конкретной даты:

const date = dayjs('2026-05-20 14:00')
date.calendar()

Логика определения контекста даты

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

  • Сегодня — если дата находится в пределах текущих суток
  • Вчера — если дата ровно на один день раньше
  • Позавчера / завтра — при близких смещениях
  • Текущая неделя — если дата попадает в диапазон нескольких дней назад или вперёд
  • Вне диапазона недели — используется обычный формат даты

Эти правила не фиксированы жёстко и могут изменяться через локаль.


Стандартные шаблоны календарного формата

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

  • sameDay — сегодняшняя дата
  • nextDay — завтра
  • nextWeek — ближайшие дни следующей недели
  • lastDay — вчера
  • lastWeek — прошлая неделя
  • sameElse — все остальные случаи

Пример логики шаблонов:

dayjs.extend(calendar, {
  sameDay: '[Today at] 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/MM/YYYY'
})

Форматирование через локаль

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

import 'dayjs/locale/ru'

dayjs.locale('ru')

После установки русской локали:

dayjs().calendar()

может возвращать:

  • «Сегодня в 14:30»
  • «Вчера в 18:00»
  • «В прошлый понедельник в 09:00»

Локали содержат предустановленные правила для календаря, включая грамматические формы дней недели и предлоги времени.


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

Переопределение поведения календаря возможно через объект calendar внутри локали.

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

После этого все вызовы .calendar() используют заданные правила.


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

Метод .calendar() может принимать аргумент — дату, относительно которой производится сравнение.

const base = dayjs('2026-05-22 12:00')
const target = dayjs('2026-05-21 18:00')

target.calendar(base)

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


Отличие calendar от fromNow

Календарное представление часто путают с относительным временем (fromNow()), однако между ними есть принципиальная разница:

  • calendar() — возвращает фиксированную временную метку с контекстом (например, «вчера в 14:00»)
  • fromNow() — возвращает разницу во времени («2 часа назад», «3 дня назад»)
dayjs().subtract(2, 'hour').calendar() // "Today at 10:00"
dayjs().subtract(2, 'hour').fromNow()  // "2 hours ago"

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


Границы недель и локальные особенности

Определение «прошлой недели» и «следующей недели» зависит от настройки начала недели (понедельник или воскресенье), которая задаётся локалью.

import 'dayjs/locale/en-gb'
dayjs.locale('en-gb')

В разных локалях:

  • начало недели может быть понедельник
  • или воскресенье

Это влияет на то, какие даты попадают в lastWeek и nextWeek.


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

Day.js позволяет задавать функцию для полного контроля над форматом.

dayjs.extend(calendar, {
  sameDay: (now) => `[Сегодня в] ${now.format('HH:mm')}`,
  lastDay: (now) => `[Вчера в] ${now.format('HH:mm')}`,
  lastWeek: (now) => `[Прошлая неделя] ${now.format('dddd HH:mm')}`,
  sameElse: (now) => now.format('DD.MM.YYYY')
})

Функция получает текущую дату контекста и может возвращать динамическую строку с любой логикой форматирования.


Работа с часовыми поясами и календарем

Calendar-представление зависит от локального времени исполнения. При использовании плагинов для временных зон (например, utc и timezone) важно учитывать, что классификация «сегодня/вчера» выполняется уже после преобразования времени.

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

dayjs.extend(utc)
dayjs.extend(timezone)

const date = dayjs.tz('2026-05-22 00:30', 'Asia/Almaty')
date.calendar()

Без корректного учета временной зоны возможно смещение даты в категорию «вчера» или «завтра».


Сравнение стандартных конфигураций календаря

Разные наборы правил дают различное восприятие времени:

Краткий формат

sameDay: 'HH:mm',
lastDay: 'HH:mm вчера',
sameElse: 'DD.MM'

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

Подробный формат

sameDay: '[Сегодня в] HH:mm:ss',
lastWeek: '[В прошлый] dddd [в] HH:mm:ss',
sameElse: 'dddd, DD MMMM YYYY'

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


Особенности интерполяции строк

При использовании строковых шаблонов квадратные скобки [] используются для экранирования текста:

'[Today at] HH:mm'

Все символы внутри скобок выводятся буквально, а вне их интерпретируются как формат времени.


Поведение при отсутствии календарной настройки

Если плагин calendar не подключен, вызов:

dayjs().calendar()

приводит к ошибке:

  • calendar is not a function

или отсутствию метода в зависимости от сборки. Это делает обязательным явное расширение функционала через extend.


Влияние локалей на грамматику времени

Локали управляют не только переводом слов, но и грамматическими формами:

  • склонение дней недели
  • согласование предлогов
  • формы «вчера», «завтра», «на прошлой неделе»

Пример:

  • «в понедельник»
  • «в прошлый понедельник»
  • «в следующий понедельник»

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


Использование calendar в пользовательских интерфейсах

Календарное представление применяется в структурах, где важна быстрая интерпретация времени:

  • списки сообщений
  • уведомления
  • журналы событий
  • истории действий пользователей
  • системы комментариев

При этом сохраняется точность временной метки, что позволяет использовать значение и для сортировки, и для отображения.


Комбинирование calendar с форматированием

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

const d = dayjs('2026-05-20 14:00')

`${d.calendar()} (${d.format('YYYY-MM-DD HH:mm')})`

Такой подход объединяет человекочитаемую форму и строгую временную метку, пригодную для логирования и аналитики.