compareAsc и compareDesc для сортировки

Функции compareAsc и compareDesc из библиотеки date-fns предназначены для унифицированного сравнения дат и используются в качестве компараторов при сортировке. Их основная задача — привести сравнение дат к строгому числовому результату, совместимому с Array.prototype.sort.

Обе функции работают с типами Date | number, где число интерпретируется как timestamp в миллисекундах.


Базовая идея сравнения дат

Сравнение дат сводится к вычислению разницы между двумя значениями времени:

  • отрицательное значение — первая дата раньше второй
  • ноль — даты равны
  • положительное значение — первая дата позже второй

В контексте date-fns это нормализуется до трёх значений:

  • -1
  • 0
  • 1

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


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

Функция compareAsc выполняет сравнение в порядке от более ранней даты к более поздней.

Сигнатура

compareAsc(dateLeft, dateRight)

Поведение

  • возвращает -1, если dateLeft раньше dateRight
  • возвращает 1, если dateLeft позже dateRight
  • возвращает 0, если значения равны

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

import { compareAsc } from 'date-fns';

const a = new Date(2023, 0, 1);
const b = new Date(2023, 0, 10);

compareAsc(a, b); // -1
compareAsc(b, a); // 1

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

import { compareAsc } from 'date-fns';

const dates = [
  new Date(2023, 5, 10),
  new Date(2021, 1, 5),
  new Date(2022, 8, 20),
];

dates.sort(compareAsc);

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


compareDesc: сортировка по убыванию

Функция compareDesc выполняет обратное сравнение: от более поздней даты к более ранней.

Сигнатура

compareDesc(dateLeft, dateRight)

Поведение

  • возвращает -1, если dateLeft позже dateRight
  • возвращает 1, если dateLeft раньше dateRight
  • возвращает 0, если значения равны

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

import { compareDesc } from 'date-fns';

const a = new Date(2023, 0, 1);
const b = new Date(2023, 0, 10);

compareDesc(a, b); // 1
compareDesc(b, a); // -1

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

import { compareDesc } from 'date-fns';

const dates = [
  new Date(2021, 1, 5),
  new Date(2023, 5, 10),
  new Date(2022, 8, 20),
];

dates.sort(compareDesc);

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


Использование с объектами

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

Сортировка по полю createdAt

import { compareAsc } from 'date-fns';

const posts = [
  { id: 1, createdAt: new Date(2023, 3, 10) },
  { id: 2, createdAt: new Date(2021, 6, 15) },
  { id: 3, createdAt: new Date(2022, 0, 1) },
];

posts.sort((a, b) => compareAsc(a.createdAt, b.createdAt));

Обратная сортировка

import { compareDesc } from 'date-fns';

posts.sort((a, b) => compareDesc(a.createdAt, b.createdAt));

Работа с числовыми timestamp

Функции одинаково работают с Date и числовыми значениями времени.

import { compareAsc } from 'date-fns';

const t1 = Date.now();
const t2 = Date.now() + 1000;

compareAsc(t1, t2); // -1

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


Влияние формата ISO-строк

compareAsc и compareDesc не принимают строки напрямую как гарантированный тип. ISO-строки необходимо преобразовывать:

import { compareAsc } from 'date-fns';

const a = new Date('2023-01-01T00:00:00Z');
const b = new Date('2023-02-01T00:00:00Z');

compareAsc(a, b);

Использование new Date() обеспечивает корректную интерпретацию временной зоны и формата.


Особенности поведения при сортировке

Стабильность сортировки

Поведение стабильности зависит от реализации движка JavaScript. В современных движках (V8, SpiderMonkey, JavaScriptCore) сортировка в большинстве случаев стабильна, однако логика компаратора не гарантирует этого на уровне спецификации.

Нормализация значений

Перед сравнением значения приводятся к числу:

  • Datetimestamp
  • number → используется напрямую

Обработка некорректных дат

Если переданы некорректные значения:

compareAsc(new Date('invalid'), new Date());

результат может быть непредсказуемым, так как Invalid Date преобразуется в NaN, а любые операции сравнения с NaN нарушают логику упорядочивания.

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


Реализация через Array.sort

Функции compareAsc и compareDesc полностью совместимы с Array.prototype.sort, так как возвращают значения, соответствующие контракту компаратора:

  • < 0 — первый элемент раньше
  • > 0 — первый элемент позже
  • 0 — равенство
array.sort(compareAsc);
array.sort(compareDesc);

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


Типовые сценарии применения

Хронологические ленты

events.sort(compareAsc);

Новостные списки

news.sort(compareDesc);

Журналы действий пользователя

logs.sort(compareDesc);

Отличие от ручного сравнения

Без date-fns сравнение обычно выглядит так:

array.sort((a, b) => a.getTime() - b.getTime());

или

array.sort((a, b) => b.getTime() - a.getTime());

Использование compareAsc и compareDesc устраняет необходимость вручную работать с getTime() и снижает вероятность ошибок при изменении структуры данных.


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

Функции представляют собой легковесные чистые операции без побочных эффектов. Основная стоимость сортировки определяется алгоритмом Array.sort, а не самим компаратором.

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


Комбинирование с другими функциями date-fns

compareAsc и compareDesc часто используются вместе с функциями преобразования и фильтрации:

  • parseISO — для разбора строк
  • isValid — для проверки корректности даты
  • format — для вывода после сортировки
import { compareDesc, parseISO } from 'date-fns';

const items = [
  { date: parseISO('2023-01-01') },
  { date: parseISO('2021-01-01') },
];

items.sort((a, b) => compareDesc(a.date, b.date));