Блокировка дат по праздничным дням в календарных интерфейсах строится вокруг механизма исключения конкретных дат из доступного диапазона выбора. В контексте Pikaday это реализуется через программное управление логикой доступности дней при отрисовке календаря. Основная цель — исключить возможность выбора дат, которые соответствуют государственным праздникам, корпоративным выходным или другим регламентированным событиям.
Праздничные даты редко выражаются простым диапазоном. Чаще это набор разрозненных значений, зависящих от страны, календарного года и даже переносов выходных. Поэтому блокировка требует структурированного подхода: нормализации дат, хранения справочника праздников и интеграции этого справочника в логику календаря.
Для корректной работы механизма блокировки праздничные даты
представляются в виде массива объектов Date, приведённых к
единому формату:
const holidays = [
new Date(2026, 0, 1), // Новый год
new Date(2026, 2, 8), // Международный женский день
new Date(2026, 4, 1), // Праздник труда
new Date(2026, 4, 9) // День Победы
];
Ключевая проблема при работе с датами — несоответствие временных зон. Для избежания ошибок сравнения применяется нормализация до полуночи:
function normalizeDate(date) {
return new Date(date.getFullYear(), date.getMonth(), date.getDate());
}
После нормализации сравнение становится предсказуемым и не зависит от локального времени пользователя.
Основной механизм блокировки в Pikaday реализуется через функцию
disableDayFn. Она вызывается для каждой даты, отображаемой
в календаре, и возвращает булево значение, определяющее доступность
дня.
Пример базовой интеграции:
const holidaysSet = new Set(
holidays.map(d => normalizeDate(d).getTime())
);
const picker = new Pikaday({
field: document.getElementById('datepicker'),
disableDayFn: function(date) {
const normalized = normalizeDate(date).getTime();
return holidaysSet.has(normalized);
}
});
Использование Set вместо массива существенно повышает
производительность, особенно при большом количестве праздничных дат,
поскольку проверка выполняется за O(1).
Статический подход применяется в случаях, когда календарь фиксирован и не зависит от внешних данных. Он удобен для локальных приложений, корпоративных систем или административных интерфейсов.
const holidays = [
'2026-01-01',
'2026-03-08',
'2026-05-01',
'2026-05-09'
];
function parseISO(dateString) {
const [y, m, d] = dateString.split('-').map(Number);
return new Date(y, m - 1, d);
}
const holidaySet = new Set(
holidays.map(d => parseISO(d).getTime())
);
Далее список подключается через disableDayFn:
const picker = new Pikaday({
field: document.getElementById('datepicker'),
disableDayFn: date => holidaySet.has(normalizeDate(date).getTime())
});
Такой подход обеспечивает стабильность и предсказуемость поведения календаря, но требует ручного обновления данных при изменении праздничного календаря.
В более сложных системах список праздников формируется динамически. Это особенно актуально для приложений, поддерживающих несколько стран или регионов.
Источники данных могут включать:
Пример загрузки с API:
async function loadHolidays(year, country) {
const response = await fetch(`/api/holidays?year=${year}&country=${country}`);
const data = await response.json();
return data.map(item => {
const [y, m, d] = item.date.split('-').map(Number);
return new Date(y, m - 1, d);
});
}
После загрузки данные интегрируются в календарь:
loadHolidays(2026, 'KZ').then(holidays => {
const set = new Set(holidays.map(d => normalizeDate(d).getTime()));
new Pikaday({
field: document.getElementById('datepicker'),
disableDayFn: date => set.has(normalizeDate(date).getTime())
});
});
Часть праздничных дней не имеет фиксированной даты. Например, религиозные праздники или переносы выходных формируются по сложным правилам.
Для таких случаев используется генерация дат на основе алгоритмов:
function getEasterDate(year) {
const f = Math.floor;
const G = year % 19;
const C = f(year / 100);
const H = (C - f(C / 4) - f((8 * C + 13) / 25) + 19 * G + 15) % 30;
const I = H - f(H / 28) * (1 - f(H / 28) * f(29 / (H + 1)) * f((21 - G) / 11));
const J = (year + f(year / 4) + I + 2 - C + f(C / 4)) % 7;
const L = I - J;
const month = 3 + f((L + 40) / 44);
const day = L + 28 - 31 * f(month / 4);
return new Date(year, month - 1, day);
}
Добавление таких дат в общий список позволяет унифицировать обработку:
const easter = getEasterDate(2026);
holidays.push(easter);
Существует три основных модели:
1. Массив Date-объектов
2. ISO-строки
3. Timestamp-сеты
В связке с Pikaday наиболее эффективным считается вариант с
Set<number> на основе нормализованных timestamp
значений.
При динамическом обновлении данных календарь должен пересоздавать
внутреннюю логику блокировки. В Pikaday это достигается пересозданием
экземпляра или обновлением функции disableDayFn.
function updatePicker(newHolidays) {
const set = new Set(newHolidays.map(d => normalizeDate(d).getTime()));
picker.config.disableDayFn = date => set.has(normalizeDate(date).getTime());
picker.draw();
}
Метод draw() инициирует повторную отрисовку календаря с
учётом новой логики блокировки.
При блокировке праздничных дат возникают нестандартные ситуации:
Пересечение с выходными Некоторые праздники совпадают с субботой или воскресеньем. В таких случаях требуется отдельная политика обработки: либо двойная блокировка, либо перенос на ближайший рабочий день.
Переходные даты между годами При смене года важно заранее подгружать праздники следующего периода, иначе выбор первых дней января может быть некорректным.
Часовые пояса Нормализация дат должна исключать влияние локального времени, иначе сравнение может давать ложные совпадения.
Блокировка праздничных дат часто связана с другими ограничениями:
В Pikaday эти правила комбинируются в единой функции:
new Pikaday({
field: document.getElementById('datepicker'),
minDate: new Date(2026, 0, 1),
maxDate: new Date(2026, 11, 31),
disableDayFn: date => {
const t = normalizeDate(date).getTime();
return holidaySet.has(t) || date.getDay() === 0;
}
});
Такой подход позволяет объединять праздничные дни и выходные в единую систему правил без дублирования логики.
При увеличении количества правил блокировки важно учитывать производительность рендера календаря. Основные оптимизации:
Set вместо массива для поискаdisableDayFnPikaday вызывает disableDayFn многократно при построении
интерфейса, поэтому любая тяжёлая логика внутри этой функции приводит к
заметной деградации UX.