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

В Day.js каждая дата представляется как неизменяемый объект, над которым выполняются операции сравнения, преобразования и вычисления разницы. Для задач фильтрации и сортировки ключевую роль играют методы сравнения: isBefore, isAfter, isSame, а также дополнительные функции для работы с границами диапазонов.

Сравнение дат

Основные методы сравнения:

  • isBefore() — проверка, что дата раньше другой
  • isAfter() — проверка, что дата позже другой
  • isSame() — проверка равенства с точностью до единицы измерения
import dayjs from 'dayjs';

const a = dayjs('2026-01-10');
const b = dayjs('2026-01-15');

a.isBefore(b); // true
a.isAfter(b);  // false
a.isSame(b);   // false

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

dayjs('2026-01-10').isSame('2026-01-10', 'day');   // true
dayjs('2026-01-10').isSame('2026-01-10 10:00', 'day'); // true

При использовании более крупных единиц (месяц, год) сравнение игнорирует младшие компоненты времени.


Фильтрация массивов дат

Типичная задача — отбор элементов массива по условию даты. Day.js применяется внутри функций filter, find, some, every.

Фильтрация по диапазону

const events = [
  { title: 'A', date: '2026-01-01' },
  { title: 'B', date: '2026-01-10' },
  { title: 'C', date: '2026-02-01' }
];

const start = dayjs('2026-01-05');
const end = dayjs('2026-01-31');

const result = events.filter(event => {
  const d = dayjs(event.date);
  return d.isAfter(start) && d.isBefore(end);
});

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


Включающие диапазоны и границы

Для включения крайних значений применяются isSame в комбинации с isAfter и isBefore:

const result = events.filter(event => {
  const d = dayjs(event.date);
  return (
    d.isAfter(start) || d.isSame(start) &&
    d.isBefore(end) || d.isSame(end)
  );
});

Более компактная форма достигается через плагин isSameOrAfter и isSameOrBefore:

import isSameOrAfter from 'dayjs/plugin/isSameOrAfter';
import isSameOrBefore from 'dayjs/plugin/isSameOrBefore';

dayjs.extend(isSameOrAfter);
dayjs.extend(isSameOrBefore);

const result = events.filter(event => {
  const d = dayjs(event.date);
  return d.isSameOrAfter(start) && d.isSameOrBefore(end);
});

Сортировка массивов по датам

Сортировка реализуется через стандартный Array.prototype.sort, где Day.js используется для сравнения временных меток.

Сортировка по возрастанию

const sorted = events.sort((a, b) => {
  return dayjs(a.date).valueOf() - dayjs(b.date).valueOf();
});

Метод valueOf() возвращает Unix timestamp в миллисекундах, что обеспечивает корректное числовое сравнение.


Сортировка по убыванию

const sortedDesc = events.sort((a, b) => {
  return dayjs(b.date).valueOf() - dayjs(a.date).valueOf();
});

Инверсия порядка достигается перестановкой операндов.


Сортировка с учетом времени и даты

При наличии временной составляющей (часы, минуты, секунды) сортировка автоматически учитывает полный timestamp:

const logs = [
  { time: '2026-05-23 10:15' },
  { time: '2026-05-23 09:30' },
  { time: '2026-05-22 18:00' }
];

logs.sort((a, b) => dayjs(a.time).diff(dayjs(b.time)));

Метод diff возвращает разницу между датами, что упрощает сравнение.


Использование diff для сортировки

diff позволяет задавать единицу измерения:

dayjs(a.date).diff(dayjs(b.date), 'day');

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


Фильтрация будущих и прошлых дат

Частая задача — разделение данных по временной оси.

Будущие события

const future = events.filter(event =>
  dayjs(event.date).isAfter(dayjs())
);

Прошедшие события

const past = events.filter(event =>
  dayjs(event.date).isBefore(dayjs())
);

Фильтрация по началу и концу периода

Методы startOf и endOf используются для нормализации диапазонов.

const startOfMonth = dayjs().startOf('month');
const endOfMonth = dayjs().endOf('month');

const monthlyEvents = events.filter(event => {
  const d = dayjs(event.date);
  return d.isAfter(startOfMonth) && d.isBefore(endOfMonth);
});

Такая конструкция исключает события вне текущего месяца и учитывает точные границы периода.


Группировка перед сортировкой

Перед сортировкой часто выполняется предварительная фильтрация по типу даты:

const validEvents = events.filter(event => dayjs(event.date).isValid());

validEvents.sort((a, b) =>
  dayjs(a.date).valueOf() - dayjs(b.date).valueOf()
);

Проверка валидности предотвращает некорректные результаты при обработке сырых данных.


Сортировка с несколькими критериями

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

events.sort((a, b) => {
  const dateDiff = dayjs(a.date).valueOf() - dayjs(b.date).valueOf();
  if (dateDiff !== 0) return dateDiff;

  return a.priority - b.priority;
});

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


Устойчивые паттерны работы с массивами дат

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

Метод sort изменяет исходный массив, поэтому часто применяется копирование:

const sorted = [...events].sort((a, b) =>
  dayjs(a.date).valueOf() - dayjs(b.date).valueOf()
);

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

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

const normalized = events.map(e => ({
  ...e,
  date: dayjs(e.date).toISOString()
}));

Оптимизация операций сравнения

При больших массивах целесообразно избегать многократного создания объектов Day.js внутри сортировки. Возможна предварительная трансформация:

const prepared = events.map(e => ({
  ...e,
  ts: dayjs(e.date).valueOf()
}));

prepared.sort((a, b) => a.ts - b.ts);

Такой подход снижает количество вычислений при сортировке и фильтрации.


Диапазонная фильтрация с числовыми метками

Использование timestamp ускоряет операции диапазонов:

const startTs = dayjs('2026-01-01').valueOf();
const endTs = dayjs('2026-01-31').valueOf();

const result = prepared.filter(e =>
  e.ts >= startTs && e.ts <= endTs
);

Числовое сравнение обеспечивает предсказуемую производительность при больших объёмах данных.


Комбинированные операции фильтрации и сортировки

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

const result = events
  .map(e => ({ ...e, ts: dayjs(e.date).valueOf() }))
  .filter(e => e.ts > dayjs('2026-01-01').valueOf())
  .sort((a, b) => a.ts - b.ts);

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