Определение рабочих дней

В библиотеке Luxon работа с датами строится вокруг объекта DateTime, который предоставляет неизменяемую (immutable) модель времени. Каждое изменение даты или времени возвращает новый экземпляр, что упрощает построение предсказуемой логики для календарных вычислений, включая определение рабочих и выходных дней.

Ключевым элементом для классификации дней недели является свойство weekday, возвращающее числовое значение от 1 до 7, где понедельник соответствует 1, а воскресенье — 7.

import { DateTime } from "luxon";

const dt = DateTime.local();
console.log(dt.weekday);

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


Базовое разделение на рабочие и выходные дни

Наиболее распространённая модель рабочего календаря предполагает, что рабочими днями считаются дни с понедельника по пятницу, а выходными — суббота и воскресенье.

Условие проверки выходного дня сводится к анализу значения weekday:

function isWeekend(date) {
  return date.weekday >= 6;
}

Соответственно, определение рабочего дня:

function isWorkday(date) {
  return date.weekday >= 1 && date.weekday <= 5;
}

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


Фильтрация диапазонов дат

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

import { DateTime } from "luxon";

function getDateRange(start, end) {
  const dates = [];
  let current = start;

  while (current <= end) {
    dates.push(current);
    current = current.plus({ days: 1 });
  }

  return dates;
}

const start = DateTime.local(2026, 1, 1);
const end = DateTime.local(2026, 1, 31);

const workdays = getDateRange(start, end).filter(d => d.weekday <= 5);

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


Учёт временных зон при определении рабочих дней

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

const dt = DateTime.now().setZone("Europe/Moscow");

console.log(dt.weekday);

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


Расширенная модель: исключение праздничных дней

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

Обычно праздничные дни хранятся в формате ISO:

const holidays = new Set([
  "2026-01-01",
  "2026-03-08",
  "2026-05-01"
]);

Проверка рабочего дня с учётом праздников:

function isBusinessDay(date, holidays) {
  const iso = date.toISODate();
  return date.weekday <= 5 && !holidays.has(iso);
}

Использование toISODate() обеспечивает нормализованное сравнение без учёта времени.


Построение календаря рабочих дней

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

function getBusinessDays(start, end, holidays) {
  const result = [];
  let current = start;

  while (current <= end) {
    if (isBusinessDay(current, holidays)) {
      result.push(current);
    }
    current = current.plus({ days: 1 });
  }

  return result;
}

Такая функция формирует последовательность, пригодную для расчётов SLA, планирования задач или построения расписаний.


Добавление N рабочих дней к дате

Одна из типовых операций — вычисление даты, отстоящей на N рабочих дней вперёд. Простое прибавление дней через plus({ days: N }) не учитывает выходные и праздники, поэтому требуется итеративный подход.

function addBusinessDays(start, count, holidays) {
  let current = start;
  let added = 0;

  while (added < count) {
    current = current.plus({ days: 1 });

    if (isBusinessDay(current, holidays)) {
      added++;
    }
  }

  return current;
}

Алгоритм опирается на последовательное продвижение по календарю с проверкой каждого дня.


Вычитание рабочих дней

Обратная операция реализуется симметрично, с движением в обратном направлении:

function subtractBusinessDays(start, count, holidays) {
  let current = start;
  let subtracted = 0;

  while (subtracted < count) {
    current = current.minus({ days: 1 });

    if (isBusinessDay(current, holidays)) {
      subtracted++;
    }
  }

  return current;
}

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


Нормализация даты перед проверкой

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

const normalized = dt.startOf("day");

Это предотвращает ситуации, когда сравнение ISO-дат может быть некорректным из-за различий во времени внутри суток.


Использование интервалов для оптимизации обхода

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

import { Interval } from "luxon";

const interval = Interval.fromDateTimes(start, end);

const days = [];
let cursor = interval.start;

while (cursor <= interval.end) {
  days.push(cursor);
  cursor = cursor.plus({ days: 1 });
}

Дальнейшая фильтрация выполняется по стандартным правилам weekday и списку праздников.


Учет региональных различий рабочей недели

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

Пример конфигурационной модели:

const calendarConfig = {
  workweek: [1, 2, 3, 4, 5], // может быть изменено
  holidays: new Set()
};

function isWorkdayCustom(date, config) {
  return config.workweek.includes(date.weekday) &&
         !config.holidays.has(date.toISODate());
}

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


Работа с ISO-строками при календарных вычислениях

Luxon активно использует ISO-форматы (toISO, toISODate) для сериализации дат. Это особенно важно при хранении списков рабочих и праздничных дней в базах данных.

const isoDate = DateTime.local().toISODate();

Использование стандартизированного формата упрощает сравнение и исключает проблемы локализации.


Оптимизация повторяющихся вычислений

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

const cache = new Map();

function isBusinessDayCached(date, holidays) {
  const key = date.toISODate();

  if (cache.has(key)) return cache.get(key);

  const result = date.weekday <= 5 && !holidays.has(key);
  cache.set(key, result);

  return result;
}

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


Композиция календарной логики

На практике определение рабочих дней редко существует изолированно. Оно становится частью более сложных вычислений: расчёта сроков задач, формирования графиков, планирования ресурсов и финансовых моделей. Luxon обеспечивает стабильную основу через DateTime, weekday, plus и minus, а бизнес-правила формируют надстройку над этой моделью, определяя конкретное поведение календаря в системе.