Метод splitBy

Interval.splitBy делит интервал на последовательность подинтервалов одинаковой длительности и возвращает массив объектов Interval, покрывающих исходный диапазон времени без пропусков и пересечений.

Основой работы метода является разбиение временного промежутка на шаги фиксированной длины, заданной через Duration-like значение. Каждый следующий элемент начинается ровно в момент окончания предыдущего, а последний подинтервал при необходимости подгоняется под границу исходного интервала.


Метод вызывается у объекта Interval:

interval.splitBy(duration: DurationLike): Interval[]

duration может задаваться в формате, который поддерживает Luxon:

  • объект Duration
  • объект с полями времени
  • строковое представление через Duration.fromObject / Duration.fromISO

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


Принцип разбиения интервала

Пусть задан интервал:

  • начало: A
  • конец: B

И задан шаг разбиения Δt.

Алгоритм формирует последовательность:

  • [A, A + Δt]
  • [A + Δt, A + 2Δt]
  • [A + 2Δt, A + 3Δt]

до тех пор, пока конец очередного сегмента не достигнет или не превысит B.

Если B не кратен Δt относительно A, последний интервал обрезается:

  • последний сегмент заканчивается ровно в B

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


Поведение на границах и округление

Разбиение происходит строго по временной шкале Luxon, без попыток «выравнивания» под календарные единицы.

Важные свойства:

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

При переходах через DST (летнее/зимнее время) фактическая длительность последнего или промежуточных интервалов в миллисекундах может отличаться от ожидаемой календарной, если используется нефиксированная длительность (например, «1 day»).


Пример базового использования

import { DateTime, Interval, Duration } from "luxon";

const start = DateTime.fromISO("2026-01-01T00:00:00");
const end = DateTime.fromISO("2026-01-01T10:00:00");

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

const parts = interval.splitBy({ hours: 2 });

Результат:

  • 00:00–02:00
  • 02:00–04:00
  • 04:00–06:00
  • 06:00–08:00
  • 08:00–10:00

Работа с неполным делением

Если длина интервала не кратна шагу:

const start = DateTime.fromISO("2026-01-01T00:00:00");
const end = DateTime.fromISO("2026-01-01T09:30:00");

const interval = Interval.fromDateTimes(start, end);
const parts = interval.splitBy({ hours: 2 });

Результат будет:

  • 00:00–02:00
  • 02:00–04:00
  • 04:00–06:00
  • 06:00–08:00
  • 08:00–09:30

Последний сегмент автоматически подстраивается под конечную границу исходного интервала.


Использование фиксированных и календарных длительностей

Luxon различает:

  • фиксированные длительности (миллисекунды)
  • календарные (hours, days, months)

При splitBy это различие критично:

Фиксированная длительность

interval.splitBy({ minutes: 30 })

Каждый шаг равен строго 30 минутам в миллисекундах.

Календарная длительность

interval.splitBy({ days: 1 })

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


Поведение при нулевой или отрицательной длительности

Передача:

  • { hours: 0 }
  • { minutes: -10 }

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


Работа с временными зонами

Так как Interval оперирует DateTime, каждый подинтервал сохраняет исходную временную зону:

const start = DateTime.fromISO("2026-03-30T00:00:00", { zone: "Europe/Berlin" });
const end = start.plus({ hours: 6 });

const interval = Interval.fromDateTimes(start, end);
const parts = interval.splitBy({ hours: 1 });

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


Отличие от разбиения через циклы

Вместо ручного построения:

let cursor = start;
const result = [];

while (cursor < end) {
  const next = cursor.plus({ hours: 1 });
  result.push(Interval.fromDateTimes(cursor, next > end ? end : next));
  cursor = next;
}

splitBy инкапсулирует:

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

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

Метод применяется в сценариях, где требуется регулярная сегментация временного диапазона:

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

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

Результат всегда представляет собой массив Interval, где:

  • каждый элемент является валидным интервалом Luxon
  • порядок строго возрастающий по времени
  • объединение всех элементов полностью покрывает исходный интервал
  • каждый последующий start равен предыдущему end

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