Валидация интервалов

В библиотеке date-fns интервал времени представляется структурой Interval, содержащей две даты: начало и конец. Базовая форма:

const interval = {
  start: new Date(2024, 0, 1),
  end: new Date(2024, 0, 10),
};

Корректная работа с интервалами предполагает соблюдение нескольких условий:

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

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


Валидация дат как базовый слой проверки

Перед работой с интервалами выполняется проверка валидности отдельных дат. В date-fns для этого используется функция isValid.

import { isValid } from "date-fns";

isValid(new Date()); // true
isValid(new Date("invalid")); // false

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

Типичная проверка интервала:

const isValidInterval = (interval) =>
  isValid(interval.start) && isValid(interval.end);

Нормализация границ интервала

Частая проблема — инвертированные границы, когда start оказывается позже end. Для корректировки используется сравнение дат.

import { compareAsc } from "date-fns";

const normalizeInterval = (interval) => {
  const order = compareAsc(interval.start, interval.end);

  if (order <= 0) {
    return interval;
  }

  return {
    start: interval.end,
    end: interval.start,
  };
};

Функция compareAsc возвращает:

  • -1, если первая дата раньше
  • 1, если позже
  • 0, если равны

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


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

Для определения попадания точки во временной диапазон используется isWithinInterval.

import { isWithinInterval } from "date-fns";

const interval = {
  start: new Date(2024, 0, 1),
  end: new Date(2024, 0, 10),
};

isWithinInterval(new Date(2024, 0, 5), interval); // true

Логика проверки включает:

  • дата должна быть больше или равна start
  • дата должна быть меньше или равна end

Границы интервала считаются включительными.


Проверка пересечения интервалов

Для анализа перекрытия временных диапазонов используется areIntervalsOverlapping.

import { areIntervalsOverlapping } from "date-fns";

const intervalA = {
  start: new Date(2024, 0, 1),
  end: new Date(2024, 0, 10),
};

const intervalB = {
  start: new Date(2024, 0, 5),
  end: new Date(2024, 0, 15),
};

areIntervalsOverlapping(intervalA, intervalB); // true

Условия пересечения:

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

Дополнительный параметр функции управляет включением границ:

areIntervalsOverlapping(intervalA, intervalB, { inclusive: false });

При inclusive: false касание границ не считается пересечением.


Сравнение границ интервалов

Базовые операции сравнения дат используются при построении более сложной логики.

Проверка порядка

import { isBefore, isAfter } from "date-fns";

isBefore(new Date(2024, 0, 1), new Date(2024, 0, 2)); // true
isAfter(new Date(2024, 0, 2), new Date(2024, 0, 1));  // true

Эти функции применяются при:

  • сортировке интервалов
  • проверке корректности границ
  • построении календарных структур

Проверка равенства дат и границ

Для точного сравнения используется isEqual.

import { isEqual } from "date-fns";

isEqual(
  new Date(2024, 0, 1),
  new Date(2024, 0, 1)
); // true

В контексте интервалов это важно для определения:

  • совпадающих диапазонов
  • вырожденных интервалов (start === end)
  • дубликатов в коллекциях интервалов

Вырожденные и пограничные интервалы

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

const interval = {
  start: new Date(2024, 0, 1),
  end: new Date(2024, 0, 1),
};

Такой интервал:

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

Пограничные случаи возникают также при соприкосновении интервалов:

  • конец одного равен началу другого
  • поведение зависит от параметра включительности в операциях пересечения

Комбинированная проверка интервала

Практическая валидация обычно объединяет несколько правил:

import { isValid, compareAsc } from "date-fns";

const validateInterval = (interval) => {
  if (!isValid(interval.start) || !isValid(interval.end)) {
    return false;
  }

  if (compareAsc(interval.start, interval.end) === 1) {
    return false;
  }

  return true;
};

Такая проверка обеспечивает:

  • корректные границы
  • отсутствие невалидных дат
  • согласованную структуру данных для последующих операций

Ошибки при работе с интервалами

Распространённые проблемы возникают при:

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

Каждая из этих ошибок приводит к некорректным результатам при фильтрации, сравнении и агрегации временных диапазонов