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

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

Внутри календаря каждый день проходит проверку перед отображением. Для этого используется callback-функция, которая получает объект даты и возвращает булево значение:

  • true — день отключён и недоступен для выбора
  • false — день доступен для взаимодействия

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

  • воскресенье — 0
  • суббота — 6

Следовательно, логика блокировки строится вокруг проверки этих значений через метод getDay() объекта Date.

Реализация через disableDayFn

Основной способ исключения выходных дней заключается в использовании опции disableDayFn.

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

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

        return false;
    }
});

В этом примере календарь будет автоматически помечать субботу и воскресенье как недоступные для выбора. Визуально такие дни обычно получают отдельный CSS-класс, задающий серый цвет и отключение событий клика.

Сокращённая форма записи

При отсутствии дополнительных условий функция может быть упрощена до одного выражения:

disableDayFn: date => date.getDay() === 0 || date.getDay() === 6

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

Совмещение с другими ограничениями

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

  • минимальная дата (minDate)
  • максимальная дата (maxDate)
  • запрет определённых диапазонов
  • исключение праздничных дней

Комбинированная логика реализуется внутри одной функции disableDayFn.

const holidays = [
    new Date(2026, 0, 1),
    new Date(2026, 4, 9)
];

function isSameDate(a, b) {
    return a.getFullYear() === b.getFullYear() &&
           a.getMonth() === b.getMonth() &&
           a.getDate() === b.getDate();
}

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

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

        for (let i = 0; i < holidays.length; i++) {
            if (isSameDate(date, holidays[i])) {
                return true;
            }
        }

        return false;
    }
});

В этом варианте логика расширяется до исключения не только выходных, но и фиксированных праздничных дат.

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

Объект Date в JavaScript может вести себя по-разному в зависимости от локальной временной зоны окружения. При использовании getDay() учитывается локальное время, что может влиять на корректность определения дня недели при работе с UTC-датами.

Если требуется строгая работа в UTC, необходимо использовать методы:

  • getUTCDay()
  • getUTCFullYear()
  • getUTCMonth()
  • getUTCDate()

Пример адаптации под UTC:

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

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

Влияние на интерфейс календаря

При возврате true из disableDayFn календарь изменяет поведение ячейки дня:

  • блокируется событие выбора
  • применяется визуальный стиль «disabled»
  • день становится недоступным для навигации с клавиатуры
  • исключается из логики автозаполнения диапазонов (если используется range selection)

Важно учитывать, что визуальное представление отключённых дней полностью зависит от CSS темы календаря. В стандартной реализации Pikaday используется класс is-disabled, который может быть переопределён.

Кастомизация внешнего вида отключённых дней

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

Пример CSS:

.is-disabled {
    opacity: 0.4;
    cursor: not-allowed;
}

.is-weekend {
    color: #d9534f;
}

Добавление отдельной метки «выходной день» возможно через расширение рендера, если требуется различать типы недоступных дат. Для этого можно комбинировать disableDayFn с логикой вычисления класса через кастомный render.

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

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

let blockWeekends = true;

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

        return false;
    }
});

// изменение поведения в рантайме
blockWeekends = false;
picker.draw();

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

Ошибки при блокировке выходных

Распространённые ошибки при реализации:

  • использование getDay вместо getUTCDay в UTC-ориентированных приложениях
  • попытка модифицировать DOM календаря напрямую вместо использования API
  • смешивание логики отображения и бизнес-правил в CSS
  • отсутствие учета диапазонов дат, что приводит к «висящим» заблокированным диапазонам

Корректная архитектура предполагает, что вся логика доступности дат централизована в disableDayFn.

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

Функция disableDayFn вызывается для каждой отображаемой ячейки календаря. При больших диапазонах дат или сложной логике (например, запросах к API) это может привести к снижению производительности.

Оптимизация достигается через:

  • предварительное вычисление множества запрещённых дат
  • использование Set для O(1) проверки
  • минимизацию вычислений внутри callback
const disabledDays = new Set([
    '2026-01-01',
    '2026-05-09'
]);

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

disableDayFn: function(date) {
    const day = date.getDay();

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

    return disabledDays.has(format(date));
}

Такой подход снижает нагрузку при рендеринге и повышает отзывчивость интерфейса.

Поведение при выборе диапазона дат

При использовании режима выбора диапазона (start/end date) блокировка выходных влияет на возможность формирования непрерывного интервала. Если внутри диапазона встречаются запрещённые даты, пользовательский сценарий может прерываться или требовать выбора альтернативного пути.

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