Сортировка выбранных дат

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

const fp = flatpickr("#input", {
  mode: "multiple"
});

При выборе дат, например:

  • 15 марта
  • 1 января
  • 10 февраля

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

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


Причины отсутствия автоматической сортировки

Flatpickr ориентируется на UX-поведение: пользовательский порядок выбора может иметь смысл в сценариях:

  • построение цепочек дат (например, лог посещений)
  • приоритетность событий
  • история выбора

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

Внутренне selectedDates — это обычный массив объектов Date, который не проходит автоматическую сортировку.


Базовая сортировка массива дат

Для приведения выбранных дат к хронологическому порядку применяется стандартная сортировка Jav * aScript:

const sorted = fp.selectedDates.slice().sort((a, b) => a - b);

Ключевой момент:

  • a и b — объекты Date
  • вычитание приводит к сравнению временных меток

Такой подход корректен и быстрый, так как Date при математических операциях автоматически приводится к timestamp.


Сортировка при каждом изменении выбора

На практике сортировку выполняют внутри обработчика onChange:

const fp = flatpickr("#input", {
  mode: "multiple",
  onChange: function(selectedDates, dateStr, instance) {
    const sorted = selectedDates.slice().sort((a, b) => a - b);

    console.log(sorted);
  }
});

Здесь важно использовать slice(), чтобы не мутировать оригинальный массив, который использует сам Flatpickr.


Формирование отсортированной строки вывода

Flatpickr предоставляет строковое представление через dateStr, но оно всегда соответствует внутреннему порядку выбора, а не сортировке.

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

const fp = flatpickr("#input", {
  mode: "multiple",
  dateFormat: "Y-m-d",
  onChange: function(selectedDates) {
    const sorted = selectedDates
      .slice()
      .sort((a, b) => a - b);

    const formatted = sorted.map(d =>
      fp.formatDate(d, "Y-m-d")
    );

    const result = formatted.join(", ");
    console.log(result);
  }
});

Такой подход обеспечивает:

  • единый формат вывода
  • корректный хронологический порядок
  • независимость от поведения UI

Влияние режима range на порядок дат

В режиме диапазона:

mode: "range"

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

  • первая дата — начало
  • вторая дата — конец
["2026-01-01", "2026-01-10"]

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

Таким образом, сортировка для range обычно не требуется, но есть исключения.


Принудительная сортировка в range-режиме

Если в приложении допускается ручное формирование массива дат (например, через API или восстановление состояния), может возникнуть необходимость перестраховаться:

function normalizeRange(dates) {
  if (!dates || dates.length !== 2) return dates;

  return dates.slice().sort((a, b) => a - b);
}

Это полезно при:

  • восстановлении состояния из localStorage
  • синхронизации с сервером
  • объединении нескольких источников данных

Работа с дубликатами и стабильная сортировка

Flatpickr в multiple-режиме позволяет выбирать одну и ту же дату только один раз, но при программной модификации массива дубликаты могут появляться.

Сортировка в таком случае не решает проблему уникальности, поэтому используется комбинация:

const uniqueSorted = Array.from(
  new Set(selectedDates.map(d => d.getTime()))
)
  .sort((a, b) => a - b)
  .map(t => new Date(t));

Здесь:

  • Set удаляет дубликаты
  • сортировка выполняется по timestamp
  • затем восстанавливаются объекты Date

Форматирование и локаль при сортировке

Сортировка всегда выполняется по времени в миллисекундах, независимо от:

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

Но при выводе важно учитывать форматирование:

fp.set("dateFormat", "d.m.Y");

или:

fp.formatDate(date, "d.m.Y H:i");

Сортировка и форматирование — два независимых этапа обработки данных.


Сортировка строковых дат (антипаттерн)

Частая ошибка — попытка сортировать строки:

selectedDates.map(d => fp.formatDate(d, "Y-m-d")).sort()

Такой подход корректен только при ISO-формате YYYY-MM-DD, где лексикографический порядок совпадает с хронологическим.

При форматах вроде:

  • DD.MM.YYYY
  • MM/DD/YYYY

сортировка строк приводит к некорректным результатам.

Правильный подход — сортировать Date, а не строки.


Использование compareFn для сложных сценариев

В сложных приложениях может потребоваться кастомная логика сортировки:

function compareDates(a, b) {
  return a.getFullYear() - b.getFullYear() ||
         a.getMonth() - b.getMonth() ||
         a.getDate() - b.getDate();
}

Этот вариант полезен, если:

  • запрещены миллисекундные сравнения
  • требуется явная читаемость логики
  • есть модификации объектов Date

Сортировка в связке с minDate и maxDate

При ограничениях диапазона:

minDate: "2026-01-01",
maxDate: "2026-12-31"

сортировка остаётся независимой, но важно учитывать:

  • отфильтрованные даты не должны попадать в массив
  • UI может визуально ограничивать выбор, но программная сортировка — нет

Поэтому иногда добавляется фильтрация:

const valid = selectedDates.filter(d =>
  d >= fp.config.minDate && d <= fp.config.maxDate
);

Сортировка при динамическом изменении данных

Flatpickr позволяет программно изменять выбранные даты:

fp.setDate(["2026-05-10", "2026-01-01", "2026-03-15"]);

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

Если требуется хронология:

fp.setDate(
  ["2026-05-10", "2026-01-01", "2026-03-15"]
    .map(d => new Date(d))
    .sort((a, b) => a - b)
);

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

При работе с HTML-формами Flatpickr часто используется как источник значения input:

const input = document.querySelector("#input");

Чтобы гарантировать отсортированное значение в поле:

onChange: function(selectedDates, dateStr, instance) {
  const sorted = selectedDates.slice().sort((a, b) => a - b);

  input.value = sorted
    .map(d => instance.formatDate(d, "Y-m-d"))
    .join(",");
}

Это особенно важно при:

  • отправке формы на сервер
  • сериализации данных
  • синхронизации с backend API

Особенности работы с временем в сортировке

Если включены временные значения:

enableTime: true

сортировка автоматически учитывает:

  • часы
  • минуты
  • секунды

Пример:

new Date("2026-05-10 10:00") < new Date("2026-05-10 12:00")

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


Типичные ошибки при сортировке выбранных дат

На практике чаще всего встречаются следующие проблемы:

  1. Сортировка строк вместо Date
  2. Мутация selectedDates напрямую
  3. Игнорирование range-логики
  4. Потеря часового пояса при преобразовании
  5. Попытка сортировать уже отформатированные значения

Каждая из этих ошибок приводит к рассинхронизации UI и внутреннего состояния Flatpickr.


Стабильная стратегия обработки

Корректный подход обработки выбранных дат строится на трёх принципах:

  • работа только с Date-объектами
  • неизменяемость исходного массива
  • сортировка перед любым выводом или сериализацией