Проверка вхождения в диапазон

В библиотеке js-joda диапазон значений представлен классом Range, который моделирует непрерывный интервал между двумя границами одного типа (например, даты, числа, моменты времени). Основная задача работы с диапазонами — проверка принадлежности значения интервалу и анализ взаимного расположения интервалов.

Диапазон в js-joda является неизменяемой структурой и оперирует исключительно сравнимыми значениями, поддерживающими естественный порядок.


Создание диапазона и его границы

Базовая форма диапазона задаётся через нижнюю и верхнюю границы:

Range.of(min, max)

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

Примеры:

import { Range } from '@js-joda/core';
import { LocalDate } from '@js-joda/core';

const start = LocalDate.of(2025, 1, 1);
const end = LocalDate.of(2025, 12, 31);

const range = Range.of(start, end);

Диапазон фиксирует порядок: min <= max. При нарушении порядка возникает ошибка времени выполнения.


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

Основной механизм проверки вхождения реализован методом:

range.contains(value)

Он возвращает логическое значение, определяющее, находится ли переданное значение внутри интервала с учётом границ.

Пример с датами

const range = Range.of(
  LocalDate.of(2025, 1, 1),
  LocalDate.of(2025, 12, 31)
);

range.contains(LocalDate.of(2025, 6, 15)); // true
range.contains(LocalDate.of(2024, 12, 31)); // false
range.contains(LocalDate.of(2026, 1, 1)); // false

Включительность границ и влияние на проверку

Диапазон может быть:

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

В js-joda также применяются специализированные конструкторы:

Range.ofClosed(min, max)
Range.ofOpen(min, max)
Range.ofOpenClosed(min, max)
Range.ofClosedOpen(min, max)

Закрытый диапазон

const range = Range.ofClosed(
  LocalDate.of(2025, 1, 1),
  LocalDate.of(2025, 1, 10)
);

range.contains(LocalDate.of(2025, 1, 1)); // true
range.contains(LocalDate.of(2025, 1, 10)); // true

Открытый диапазон

const range = Range.ofOpen(
  LocalDate.of(2025, 1, 1),
  LocalDate.of(2025, 1, 10)
);

range.contains(LocalDate.of(2025, 1, 1)); // false
range.contains(LocalDate.of(2025, 1, 10)); // false

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

js-joda поддерживает диапазоны для всех основных типов времени:

  • LocalDate
  • LocalDateTime
  • Instant
  • YearMonth
  • ZonedDateTime

Instant как пример абсолютного времени

import { Instant, Range } from '@js-joda/core';

const start = Instant.parse('2025-01-01T00:00:00Z');
const end = Instant.parse('2025-01-02T00:00:00Z');

const range = Range.of(start, end);

range.contains(Instant.parse('2025-01-01T12:00:00Z')); // true

Особенности сравнения внутри диапазона

Диапазон опирается на естественный порядок элементов через метод compareTo. Это означает:

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

Пример некорректной логики:

Range.of(LocalDate.now(), Instant.now()); // ошибка несовместимых типов

Граничные случаи и поведение contains

Проверка принадлежности имеет строгую семантику:

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

Пример поведения на границах:

const range = Range.ofClosed(
  LocalDate.of(2025, 5, 1),
  LocalDate.of(2025, 5, 10)
);

range.contains(LocalDate.of(2025, 5, 1));  // true
range.contains(LocalDate.of(2025, 5, 10)); // true

Пересечение диапазона как расширенная форма проверки

Хотя основной акцент делается на contains, часто используется проверка пересечения:

range.isConnected(otherRange)

или логика через:

range.encloses(otherRange)

Эти методы позволяют определить отношение диапазонов без проверки конкретного значения.


Типовая схема использования проверки принадлежности

Проверка contains применяется в следующих сценариях:

  • фильтрация событий по времени
  • валидация дат в бизнес-логике
  • проверка попадания значения в разрешённый интервал
  • сегментация временных рядов

Пример фильтрации:

const events = [
  LocalDate.of(2025, 1, 1),
  LocalDate.of(2025, 6, 1),
  LocalDate.of(2026, 1, 1)
];

const range = Range.ofClosed(
  LocalDate.of(2025, 1, 1),
  LocalDate.of(2025, 12, 31)
);

const filtered = events.filter(e => range.contains(e));

Поведение при пустых диапазонах

Диапазон, в котором границы совпадают при открытом типе, может считаться пустым:

const range = Range.ofOpen(
  LocalDate.of(2025, 1, 1),
  LocalDate.of(2025, 1, 1)
);

range.contains(LocalDate.of(2025, 1, 1)); // false

Это важно учитывать при динамическом формировании интервалов.


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

Операция contains имеет константную сложность:

  • не зависит от размера диапазона
  • использует только сравнение границ
  • не требует перебора элементов

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