Блокировка дат по дням недели

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

Модель работы дней недели в JavaScript Date

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

  • 0 — воскресенье
  • 1 — понедельник
  • 2 — вторник
  • 3 — среда
  • 4 — четверг
  • 5 — пятница
  • 6 — суббота

Метод date.getDay() возвращает одно из этих значений, что делает его базовым инструментом для построения условий блокировки.

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

Функция disableDayFn вызывается для каждой даты, отображаемой в календаре. Если функция возвращает true, дата становится недоступной для выбора.

Блокировка, например, всех понедельников реализуется следующим образом:

var picker = new Pikaday({
    field: document.getElementById('datepicker'),
    disableDayFn: function(date) {
        return date.getDay() === 1;
    }
});

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

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

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

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

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

Использование массива запрещённых дней

При росте количества условий удобнее выносить конфигурацию в массив, что делает код более декларативным:

var disabledDays = [0, 6];

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

Данный вариант упрощает поддержку, особенно если список блокируемых дней формируется динамически.

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

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

Пример блокировки среды и пятницы:

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

        if (day === 3 || day === 5) {
            return true;
        }

        return false;
    }
});

Логика может быть расширена до проверки внешних переменных:

var isMaintenanceDay = true;

var picker = new Pikaday({
    field: document.getElementById('datepicker'),
    disableDayFn: function(date) {
        if (isMaintenanceDay) {
            return date.getDay() !== 1; // разрешён только понедельник
        }
        return false;
    }
});

Комбинирование с ограничением диапазона дат

disableDayFn часто используется вместе с minDate и maxDate. В этом случае сначала отсекается диапазон, а затем применяется фильтрация по дням недели:

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() === 0 || date.getDay() === 6;
    }
});

Такой подход позволяет задавать одновременно временные рамки и календарные правила.

Инвертированная логика разрешённых дней

Иногда удобнее мыслить не запрещёнными, а разрешёнными днями. Тогда логика строится через явный whitelist:

var allowedDays = [1, 2, 3, 4, 5];

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

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

Условная блокировка по типу даты

Функция disableDayFn работает не только с днями недели, но и с любыми свойствами объекта Date. Это позволяет комбинировать фильтрацию:

var picker = new Pikaday({
    field: document.getElementById('datepicker'),
    disableDayFn: function(date) {
        var day = date.getDay();
        var dayOfMonth = date.getDate();

        if (day === 0 || day === 6) {
            return true;
        }

        if (dayOfMonth === 13) {
            return true;
        }

        return false;
    }
});

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

Централизация логики фильтрации

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

function isDateDisabled(date) {
    var day = date.getDay();

    var isWeekend = (day === 0 || day === 6);
    var isHolidayRule = (day === 2);

    return isWeekend || isHolidayRule;
}

var picker = new Pikaday({
    field: document.getElementById('datepicker'),
    disableDayFn: isDateDisabled
});

Такая структура повышает тестируемость логики и упрощает её переиспользование в разных календарях приложения.

Изменение правил блокировки во время выполнения

Pikaday позволяет пересоздавать или переинициализировать календарь с новыми правилами, что используется для динамического изменения доступности дней:

var currentRule = 'standard';

function getDisableFn() {
    return function(date) {
        var day = date.getDay();

        if (currentRule === 'standard') {
            return day === 0 || day === 6;
        }

        if (currentRule === 'strict') {
            return day !== 1;
        }

        return false;
    };
}

var picker = new Pikaday({
    field: document.getElementById('datepicker'),
    disableDayFn: getDisableFn()
});

При изменении currentRule можно пересоздать экземпляр календаря для применения новой логики.

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

Функция disableDayFn вызывается для каждой отображаемой ячейки календаря, поэтому:

  • логика внутри должна быть максимально лёгкой;
  • не рекомендуется выполнять тяжёлые вычисления или сетевые запросы;
  • внешние данные лучше кэшировать заранее.

Пример оптимизированного подхода:

var disabledSet = new Set([0, 6]);

var picker = new Pikaday({
    field: document.getElementById('datepicker'),
    disableDayFn: function(date) {
        return disabledSet.has(date.getDay());
    }
});

Использование Set обеспечивает постоянную сложность проверки и снижает нагрузку при больших календарных диапазонах.

Типичные ошибки при блокировке дней недели

Распространённые проблемы связаны не с Pikaday, а с логикой даты:

  • использование getDay() вместо getDate() при попытке блокировать числа месяца;
  • игнорирование локального часового пояса при создании Date;
  • смешивание условий «разрешено» и «запрещено» без явной структуры;
  • возврат undefined вместо true/false, что приводит к непредсказуемому поведению.

Корректная реализация всегда возвращает строго булево значение.

Структурирование сложных календарных правил

При наличии множества условий удобно формировать отдельные правила:

var rules = {
    weekends: function(date) {
        var d = date.getDay();
        return d === 0 || d === 6;
    },
    wednesdayOnly: function(date) {
        return date.getDay() !== 3;
    },
    noMondays: function(date) {
        return date.getDay() === 1;
    }
};

var activeRule = rules.weekends;

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

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