В задачах работы с датами и временем одной из ключевых операций
становится определение пересечения интервалов. В контексте
js-joda это проявляется при анализе диапазонов дат,
проверке конфликтов расписаний, объединении событий и построении
временных выборок.
Основная сложность заключается в том, что разные типы временных
сущностей (LocalDate, LocalDateTime,
Instant) требуют разных подходов к сравнению, а также в
необходимости учитывать границы интервалов: включительные они или
исключительные.
Два интервала считаются пересекающимися, если существует хотя бы одна точка времени, которая принадлежит обоим диапазонам.
Для интервалов:
пересечение существует, если:
aStart < bEnd и bStart < aEndЭто универсальное правило применимо ко всем линейным временным шкалам.
В экосистеме js-joda работа с полноценными временными интервалами
реализуется через пакет js-joda-extra, где представлен
класс Interval.
Интервал строится на основе Instant:
import { Instant } from '@js-joda/core';
import { Interval } from '@js-joda/extra';
const startA = Instant.parse('2026-01-01T10:00:00Z');
const endA = Instant.parse('2026-01-01T12:00:00Z');
const startB = Instant.parse('2026-01-01T11:00:00Z');
const endB = Instant.parse('2026-01-01T13:00:00Z');
const intervalA = Interval.of(startA, endA);
const intervalB = Interval.of(startB, endB);
Класс Interval предоставляет метод
overlaps, который определяет наличие пересечения между
двумя интервалами.
const result = intervalA.overlaps(intervalB);
Результат:
true — интервалы пересекаютсяfalse — пересечения нетЛогика метода основана на проверке границ интервалов без необходимости ручного сравнения.
Пересечение интервалов часто путается с другими отношениями:
Интервал A включает B, если:
intervalA.contains(intervalB);
Интервалы могут не пересекаться, но соприкасаться:
intervalA.abuts(intervalB);
Такие интервалы не считаются пересекающимися, несмотря на отсутствие промежутка между ними.
Если пересечение существует, его можно вычислить:
const intersection = intervalA.intersection(intervalB);
Результатом будет новый Interval, соответствующий общей
части диапазонов.
При отсутствии пересечения операция приводит к ошибке, поэтому перед вызовом используется проверка:
if (intervalA.overlaps(intervalB)) {
const intersection = intervalA.intersection(intervalB);
}
Формально пересечение интервалов A и B определяется через границы:
Если start < end, пересечение существует.
const start = aStart.isAfter(bStart) ? aStart : bStart;
const end = aEnd.isBefore(bEnd) ? aEnd : bEnd;
const hasIntersection = start.isBefore(end);
Эта модель полезна при работе без Interval, например при
использовании только LocalDateTime.
LocalDate не содержит встроенного класса интервалов,
поэтому проверка выполняется вручную.
import { LocalDate } from '@js-joda/core';
const startA = LocalDate.parse('2026-01-01');
const endA = LocalDate.parse('2026-01-10');
const startB = LocalDate.parse('2026-01-05');
const endB = LocalDate.parse('2026-01-15');
Условие пересечения:
const overlaps =
(startA.isBefore(endB) || startA.equals(endB)) &&
(startB.isBefore(endA) || startB.equals(endA));
Такой подход учитывает включительные границы, характерные для дат без времени.
IntervalПри работе с массивами интервалов задача сводится к поиску всех пересекающихся пар.
const intervals = [intervalA, intervalB, intervalC];
for (let i = 0; i < intervals.length; i++) {
for (let j = i + 1; j < intervals.length; j++) {
if (intervals[i].overlaps(intervals[j])) {
// обработка пересечения
}
}
}
Сложность такого подхода — O(n²), что становится критичным при больших наборах данных.
Упорядочивание интервалов по началу позволяет сократить количество проверок:
const sorted = intervals.sort((a, b) =>
a.start().compareTo(b.start())
);
for (let i = 0; i < sorted.length; i++) {
for (let j = i + 1; j < sorted.length; j++) {
if (!sorted[i].overlaps(sorted[j])) {
break;
}
}
}
После выхода за пределы пересечения дальнейшие проверки для текущего интервала становятся избыточными.
При использовании ZonedDateTime пересечения могут
изменяться при смене временной зоны.
Приведение к Instant устраняет неоднозначность:
const instantA = zonedDateTimeA.toInstant();
const instantB = zonedDateTimeB.toInstant();
const intervalA = Interval.of(instantA, instantA.plusSeconds(3600));
const intervalB = Interval.of(instantB, instantB.plusSeconds(3600));
Если начало и конец совпадают:
Если start > end:
overlaps возвращает falseabuts возвращает trueoverlaps — наличие общей областиcontains — вложенность интервалаintersection — получение пересеченияabuts — проверка соприкосновения границЭти операции формируют базовый набор для анализа временных диапазонов в js-joda и позволяют строить сложные системы планирования и синхронизации данных.