Работа с диапазонами дат в интерфейсах отчётности строится вокруг необходимости задать начальную и конечную границу временного интервала, который затем используется для фильтрации данных на сервере или в клиентской логике. В экосистеме JavaScript одной из наиболее удобных библиотек для этих задач выступает Flatpickr, предоставляющая режим выбора диапазона без необходимости писать собственную логику парсинга, валидации и отображения календаря.
range как фундамент отчётных интерваловКлючевой механизм, позволяющий работать с диапазонами, — это режим:
flatpickr("#reportRange", {
mode: "range"
});
В этом режиме пользователь последовательно выбирает две даты:
После выбора библиотека автоматически формирует строку вида:
2026-06-01 to 2026-06-15
или в зависимости от настроек форматирования:
01.06.2026 - 15.06.2026
Flatpickr хранит диапазон как массив из двух элементов:
[selectedStart, selectedEnd]
Если конечная дата не выбрана, второй элемент остаётся
null, что важно учитывать при построении отчётной
логики.
Отчётные системы почти всегда требуют строгого формата дат, например:
YYYY-MM-DDНастройка:
flatpickr("#reportRange", {
mode: "range",
dateFormat: "Y-m-d"
});
По умолчанию Flatpickr использует разделитель " to ", но
его часто заменяют на более нейтральный:
flatpickr("#reportRange", {
mode: "range",
dateFormat: "Y-m-d",
rangeSeparator: " — "
});
Это важно для систем, где строка диапазона отображается в UI-логах или печатных формах отчётов.
В реальных системах отчётности диапазон почти всегда ограничивается бизнес-правилами:
flatpickr("#reportRange", {
mode: "range",
minDate: "2026-01-01",
maxDate: "2026-12-31"
});
const today = new Date();
const thirtyDaysAgo = new Date();
thirtyDaysAgo.setDate(today.getDate() - 30);
flatpickr("#reportRange", {
mode: "range",
minDate: thirtyDaysAgo,
maxDate: today
});
Такой подход используется для предотвращения запросов к слишком объёмным выборкам данных.
В отчётных системах часто требуется заранее заданный период:
const end = new Date();
const start = new Date();
start.setDate(end.getDate() - 7);
flatpickr("#reportRange", {
mode: "range",
defaultDate: [start, end]
});
const now = new Date();
const start = new Date(now.getFullYear(), now.getMonth(), 1);
const end = new Date(now.getFullYear(), now.getMonth() + 1, 0);
flatpickr("#reportRange", {
mode: "range",
defaultDate: [start, end]
});
Основная логика отчётности строится вокруг события
onChange.
flatpickr("#reportRange", {
mode: "range",
dateFormat: "Y-m-d",
onChange: function(selectedDates) {
const [start, end] = selectedDates;
if (!start || !end) return;
fetchReports({
from: start.toISOString(),
to: end.toISOString()
});
}
});
Flatpickr может возвращать:
Поэтому обязательна проверка завершённости диапазона.
Разные системы требуют разную нормализацию:
function normalizeRange([start, end]) {
const from = new Date(start);
from.setHours(0, 0, 0, 0);
const to = new Date(end);
to.setHours(23, 59, 59, 999);
return { from, to };
}
Это критично для отчётов, где учитываются все события за сутки.
const fromUTC = new Date(Date.UTC(
start.getFullYear(),
start.getMonth(),
start.getDate()
));
Используется при аналитике, где важна консистентность между часовыми поясами.
Несмотря на встроенные ограничения Flatpickr, бизнес-валидация часто требуется дополнительно.
function validateRange(start, end) {
const diff = (end - start) / (1000 * 60 * 60 * 24);
if (diff > 30) {
throw new Error("Диапазон не может превышать 30 дней");
}
}
Пользователь может выбрать:
Flatpickr нормализует порядок дат, но бизнес-логика должна учитывать крайние случаи.
В режиме range библиотека автоматически
подсвечивает:
Однако для отчётных интерфейсов важно учитывать плотные диапазоны, где визуальная перегрузка может мешать восприятию.
flatpickr("#reportRange", {
mode: "range",
showMonths: 2
});
Два месяца одновременно улучшают выбор больших периодов, особенно в аналитических панелях.
Диапазон дат в Flatpickr не должен напрямую считаться финальным источником истины. Обычно архитектура строится так:
Пример промежуточного состояния:
const state = {
range: null
};
flatpickr("#reportRange", {
mode: "range",
onChange(selectedDates) {
if (selectedDates.length === 2) {
state.range = normalizeRange(selectedDates);
}
}
});
Диапазон почти всегда превращается в параметры запроса:
GET /reports?from=2026-06-01&to=2026-06-15
Или POST-запрос:
fetch("/reports", {
method: "POST",
body: JSON.stringify({
from,
to
})
});
Важно, что Flatpickr не навязывает формат API — он лишь поставляет структурированные даты.
При повторном открытии календаря важно восстановить состояние:
flatpickr("#reportRange", {
mode: "range",
defaultDate: [savedStart, savedEnd]
});
Если сохраняется только строка:
2026-06-01 to 2026-06-15
её необходимо разобрать:
const [startStr, endStr] = saved.split(" to ");
Если пользователь выбирает только одну дату и закрывает календарь, возможны сценарии:
В отчётных интерфейсах чаще используется стратегия:
onClose(selectedDates) {
if (selectedDates.length !== 2) {
clearReportFilter();
}
}
В отчётных системах часто блокируются:
flatpickr("#reportRange", {
mode: "range",
disable: [
"2026-01-01",
"2026-05-09"
]
});
Или через функцию:
disable: [
function(date) {
return date.getDay() === 0; // воскресенье
}
]
При работе с аналитическими системами диапазоны могут достигать месяцев и лет. В таких случаях используются:
Пример пресетов:
document.querySelector("#lastMonth").oncl ick = () => {
const end = new Date();
const start = new Date();
start.setMonth(start.getMonth() - 1);
fp.setDate([start, end]);
};
Flatpickr поддерживает локализацию, влияющую на отображение диапазонов:
import { Russian } from "flatpickr/dist/l10n/ru.js";
flatpickr("#reportRange", {
mode: "range",
locale: Russian
});
Это влияет только на UI, но не на внутренние значения дат.
При работе с глобальными системами отчётности критично учитывать:
Flatpickr всегда оперирует локальными Date-объектами, поэтому финальная нормализация должна происходить вне библиотеки.
flatpickr("#reportRange", {
mode: "range",
onChange(selectedDates) {
if (selectedDates.length === 0) {
resetReport();
}
}
});
Очистка может происходить:
Диапазон дат становится центральным фильтром:
Каждый из этих сценариев требует одинаковой структуры данных:
[startDate, endDate]
с последующей трансформацией в формат, понятный backend-системе.