Метод union

Назначение и смысл операции объединения

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

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


Контекст применения Interval в Luxon

В Luxon временной интервал представлен объектом Interval, который описывается двумя границами:

  • начало (start)
  • конец (end)

Интервалы могут:

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

Метод union применяется для нормализации таких наборов.


Сигнатура и форма использования

В Luxon объединение интервалов реализуется как статический метод:

Interval.union(intervals)

или как метод экземпляра:

interval.union(...intervals)

Параметры:

  • intervals — массив или набор объектов Interval

Возвращаемое значение:

  • массив Interval[], содержащий объединённые непрерывные интервалы

Логика работы метода union

Алгоритм объединения выполняет несколько шагов:

  1. Сортировка интервалов по времени начала
  2. Последовательное сравнение текущего и следующего интервала
  3. Проверка пересечения или смежности
  4. Слияние при необходимости
  5. Формирование нового массива интервалов

Ключевой принцип: любые интервалы, у которых start <= предыдущий.end, подлежат объединению.


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

Рассмотрим пересекающиеся интервалы:

import { Interval, DateTime } from "luxon";

const i1 = Interval.fromDateTimes(
  DateTime.fromISO("2024-01-01T10:00"),
  DateTime.fromISO("2024-01-01T12:00")
);

const i2 = Interval.fromDateTimes(
  DateTime.fromISO("2024-01-01T11:00"),
  DateTime.fromISO("2024-01-01T13:00")
);

const result = Interval.union([i1, i2]);

Результат:

  • один интервал: 10:00 → 13:00

Логика объединения основана на расширении границ:

  • начало = минимум начальных точек
  • конец = максимум конечных точек

Объединение смежных интервалов

Смежные интервалы — это такие, где конец одного совпадает с началом другого.

const i1 = Interval.fromDateTimes(
  DateTime.fromISO("2024-01-01T08:00"),
  DateTime.fromISO("2024-01-01T10:00")
);

const i2 = Interval.fromDateTimes(
  DateTime.fromISO("2024-01-01T10:00"),
  DateTime.fromISO("2024-01-01T12:00")
);

const result = Interval.union([i1, i2]);

Результат:

  • один интервал: 08:00 → 12:00

Смежность рассматривается как частный случай объединения без разрыва.


Разрозненные интервалы

Если интервалы не пересекаются и не соприкасаются, объединение не происходит:

const i1 = Interval.fromDateTimes(
  DateTime.fromISO("2024-01-01T08:00"),
  DateTime.fromISO("2024-01-01T09:00")
);

const i2 = Interval.fromDateTimes(
  DateTime.fromISO("2024-01-01T10:00"),
  DateTime.fromISO("2024-01-01T11:00")
);

const result = Interval.union([i1, i2]);

Результат:

  • два отдельных интервала остаются без изменений

Объединение множества интервалов

Метод корректно работает с произвольным количеством интервалов:

const intervals = [
  Interval.fromDateTimes(DateTime.fromISO("2024-01-01T09:00"), DateTime.fromISO("2024-01-01T11:00")),
  Interval.fromDateTimes(DateTime.fromISO("2024-01-01T10:30"), DateTime.fromISO("2024-01-01T12:00")),
  Interval.fromDateTimes(DateTime.fromISO("2024-01-01T13:00"), DateTime.fromISO("2024-01-01T14:00")),
  Interval.fromDateTimes(DateTime.fromISO("2024-01-01T13:30"), DateTime.fromISO("2024-01-01T15:00"))
];

const result = Interval.union(intervals);

Результат:

  • 09:00 → 12:00
  • 13:00 → 15:00

Происходит каскадное объединение внутри групп пересечений.


Внутренняя модель объединения

Логика сводится к жадному алгоритму:

  • текущий интервал становится базой
  • следующий либо расширяет его, либо завершает группу
  • при расширении обновляются границы
  • при разрыве создаётся новый интервал

Ключевые свойства:

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

Отличие union от intersection

Операции часто путаются, но их смысл противоположен:

  • union — объединяет все покрытия воедино
  • intersection — возвращает пересечение общих частей

Пример различия:

  • интервалы: 10:00–12:00 и 11:00–13:00

    • union → 10:00–13:00
    • intersection → 11:00–12:00

Особенности работы с пустыми результатами

Если входной массив пуст:

Interval.union([])

результат:

  • пустой массив

Если передан один интервал:

  • возвращается он же без изменений

Обработка некорректных данных

Luxon предполагает, что входные интервалы валидны:

  • start < end
  • корректные DateTime

Некорректные интервалы могут привести к непредсказуемому результату или игнорированию при объединении.


Практическое применение

Нормализация расписаний

При обработке занятости пользователей интервалы часто пересекаются:

  • встречи
  • события календаря
  • бронирования

union позволяет получить итоговую занятость без дублирования времени.


Анализ покрытия времени

При подсчёте:

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

объединение помогает получить компактное представление сегментов.


Оптимизация хранения данных

В системах, где важно хранить временные диапазоны:

  • уменьшается количество записей
  • упрощается последующая аналитика
  • снижается сложность поиска пересечений

Поведение с большим количеством интервалов

При работе с большим набором данных:

  • сначала выполняется сортировка по start
  • затем линейный проход
  • итоговая сложность: O(n log n)

Оптимизация достигается за счёт отсутствия вложенных циклов.


Каскадное объединение

Особый случай возникает, когда интервалы образуют цепочку пересечений:

  • A пересекается с B
  • B пересекается с C
  • A не пересекается напрямую с C

Результат union объединяет их в один интервал, так как транзитивное перекрытие учитывается через промежуточный элемент.


Использование в цепочках обработки данных

Метод часто применяется в комбинации с другими операциями Interval:

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

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