Блокировка произвольных дат через функцию

В библиотеке Pikaday механизм ограничения доступных дат реализуется не только через статические параметры minDate и maxDate, но и через функциональный подход, позволяющий вычислять доступность каждой конкретной даты в момент её отрисовки. Основным инструментом для этого выступает disableDayFn, принимающий функцию-предикат, возвращающую логическое значение для каждой проверяемой даты.

Такой подход обеспечивает динамическую модель блокировок, где логика определяется произвольными условиями: календарными правилами, бизнес-ограничениями, внешними данными или комбинированными сценариями.


Механизм работы disableDayFn

При инициализации календаря каждая дата, которая должна быть отображена в сетке месяца, проходит проверку через функцию:

disableDayFn: function(date) {
    return false; // дата доступна
}

Если функция возвращает true, дата считается недоступной для выбора и визуально блокируется в интерфейсе. Если возвращается false, дата остаётся активной.

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


Базовая инициализация с функцией блокировки

var picker = new Pikaday({
    field: document.getElementById('datepicker'),
    disableDayFn: function(date) {
        return date.getDay() === 0; // блокировка воскресений
    }
});

В данном случае используется метод getDay(), возвращающий день недели (0 — воскресенье). Такой подход часто применяется для исключения выходных или отдельных рабочих дней.


Блокировка выходных дней

Частый сценарий — отключение суббот и воскресений:

disableDayFn: function(date) {
    var day = date.getDay();
    return (day === 0 || day === 6);
}

Логика предельно проста и масштабируема: добавление дополнительных условий не нарушает структуру функции.


Ограничение прошедших дат

Функциональная блокировка позволяет легко исключить все даты до текущего дня:

var today = new Date();
today.setHours(0, 0, 0, 0);

var picker = new Pikaday({
    field: document.getElementById('datepicker'),
    disableDayFn: function(date) {
        var normalized = new Date(date.getFullYear(), date.getMonth(), date.getDate());
        return normalized < today;
    }
});

Нормализация времени до полуночи предотвращает ошибки, связанные с часовыми смещениями и сравнением объектов Date с разным временем.


Блокировка конкретного набора дат

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

var blockedDates = [
    '2026-01-01',
    '2026-01-07',
    '2026-05-09'
];

function format(date) {
    var y = date.getFullYear();
    var m = String(date.getMonth() + 1).padStart(2, '0');
    var d = String(date.getDate()).padStart(2, '0');
    return y + '-' + m + '-' + d;
}

var picker = new Pikaday({
    field: document.getElementById('datepicker'),
    disableDayFn: function(date) {
        return blockedDates.indexOf(format(date)) !== -1;
    }
});

Такая модель удобна для интеграции с серверными API, где список недоступных дат может обновляться динамически.


Динамическая генерация правил блокировки

Функция может включать сложные вычисления, основанные на бизнес-логике. Например, блокировка всех дат, попадающих в определённый диапазон месяцев:

var picker = new Pikaday({
    field: document.getElementById('datepicker'),
    disableDayFn: function(date) {
        var month = date.getMonth();
        return month === 6 || month === 7; // июль и август недоступны
    }
});

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


Комбинирование условий

Функциональная природа disableDayFn позволяет объединять несколько правил в одной точке контроля.

var picker = new Pikaday({
    field: document.getElementById('datepicker'),
    disableDayFn: function(date) {
        var day = date.getDay();
        var isWeekend = (day === 0 || day === 6);

        var today = new Date();
        today.setHours(0, 0, 0, 0);

        var current = new Date(date.getFullYear(), date.getMonth(), date.getDate());
        var isPast = current < today;

        return isWeekend || isPast;
    }
});

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


Использование внешних данных

В реальных приложениях данные о блокировках часто поступают извне. Это может быть ответ API, конфигурация сервера или состояние системы.

var unavailableMap = {
    '2026-02-10': true,
    '2026-02-11': true,
    '2026-02-12': false
};

function format(date) {
    return date.toISOString().slice(0, 10);
}

var picker = new Pikaday({
    field: document.getElementById('datepicker'),
    disableDayFn: function(date) {
        return !!unavailableMap[format(date)];
    }
});

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


Условная блокировка по времени суток

Хотя Pikaday работает на уровне даты, возможно добавление контекста времени через внешние переменные состояния.

var cutoffHour = 15; // 15:00

var picker = new Pikaday({
    field: document.getElementById('datepicker'),
    disableDayFn: function(date) {
        var now = new Date();

        var isToday =
            date.getFullYear() === now.getFullYear() &&
            date.getMonth() === now.getMonth() &&
            date.getDate() === now.getDate();

        if (!isToday) {
            return false;
        }

        return now.getHours() >= cutoffHour;
    }
});

В результате текущий день становится недоступным после определённого времени.


Приоритет minDate, maxDate и disableDayFn

minDate и maxDate задают жесткие границы диапазона, в то время как disableDayFn работает внутри этих границ, уточняя доступность отдельных дат.

var picker = new Pikaday({
    field: document.getElementById('datepicker'),
    minDate: new Date(2026, 0, 1),
    maxDate: new Date(2026, 11, 31),
    disableDayFn: function(date) {
        return date.getDay() === 1; // блокировка понедельников
    }
});

Даже если дата входит в допустимый диапазон, она может быть отключена функцией.


Оптимизация сложной логики блокировок

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

var cache = {};

function computeKey(date) {
    return date.getFullYear() + '-' + date.getMonth() + '-' + date.getDate();
}

var picker = new Pikaday({
    field: document.getElementById('datepicker'),
    disableDayFn: function(date) {
        var key = computeKey(date);

        if (cache[key] !== undefined) {
            return cache[key];
        }

        var result =
            date.getDay() === 0 ||
            date.getDay() === 6;

        cache[key] = result;
        return result;
    }
});

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


Гибридная модель правил блокировки

На практике функциональная блокировка часто комбинируется с предрасчитанными наборами дат и динамическими условиями.

var holidays = new Set(['2026-01-01', '2026-12-31']);

function format(date) {
    return date.toISOString().slice(0, 10);
}

var picker = new Pikaday({
    field: document.getElementById('datepicker'),
    minDate: new Date(2026, 0, 1),
    maxDate: new Date(2026, 11, 31),
    disableDayFn: function(date) {
        var isWeekend = date.getDay() === 0 || date.getDay() === 6;
        var isHoliday = holidays.has(format(date));

        return isWeekend || isHoliday;
    }
});