Метод startOf

Метод startOf(unit) в Luxon используется для нормализации момента времени к началу указанного временного интервала. Он возвращает новый объект DateTime, в котором все меньшие компоненты даты и времени обнулены в соответствии с выбранной единицей измерения. Оригинальный объект при этом не изменяется, поскольку DateTime в Luxon является иммутабельным.


startOf выполняет «срез» времени по заданной единице:

  • для дня — устанавливает время на 00:00:00.000
  • для часа — на XX:00:00.000
  • для минуты — на XX:XX:00.000
  • для месяца — на первый день месяца, 00:00:00.000
  • для года — на 1 января, 00:00:00.000

Обобщённо: все более мелкие компоненты обнуляются, более крупные сохраняются.

Сигнатура:

DateTime.startOf(unit: string): DateTime

Параметр unit задаёт уровень округления.


Поддерживаемые единицы измерения

Luxon поддерживает широкий набор значений unit, включая:

  • "year"
  • "quarter"
  • "month"
  • "week"
  • "day"
  • "hour"
  • "minute"
  • "second"
  • "millisecond"

Каждая единица влияет на набор полей, которые будут сброшены.


Поведение на уровне дня

Наиболее частое применение связано с нормализацией даты до начала суток:

const dt = DateTime.local(2026, 5, 23, 18, 45);
const start = dt.startOf("day");

Результат:

  • дата сохраняется: 2026-05-23
  • время становится: 00:00:00.000

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


Поведение на уровне месяца

const dt = DateTime.local(2026, 5, 23, 18, 45);
const start = dt.startOf("month");

Результат:

  • дата: 2026-05-01
  • время: 00:00:00.000

Все дни месяца «схлопываются» к первому дню.


Поведение на уровне года

const dt = DateTime.local(2026, 5, 23);
const start = dt.startOf("year");

Результат:

  • 2026-01-01 00:00:00.000

Используется для построения годовых диапазонов, отчетности и агрегации.


Час, минута, секунда

При более мелких единицах метод работает аналогично:

const dt = DateTime.local(2026, 5, 23, 18, 45, 33, 123);

dt.startOf("hour");   // 18:00:00.000
dt.startOf("minute"); // 18:45:00.000
dt.startOf("second"); // 18:45:33.000

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


Недельная логика и локаль

Особое поведение наблюдается для "week". Начало недели зависит от локали и настроек календаря.

В Luxon неделя определяется через локализацию, в частности:

  • первый день недели может быть понедельником или воскресеньем
  • используется ISO-неделя или локальный стандарт

Пример:

const dt = DateTime.local(2026, 5, 23);
const start = dt.startOf("week");

Результат зависит от конфигурации locale и календарных настроек. В большинстве европейских локалей неделя начинается с понедельника, в некоторых — с воскресенья.

Это критически важно при построении календарных сеток и недельной агрегации данных.


Квартальная логика

dt.startOf("quarter");

Кварталы определяются стандартно:

  • Q1: январь – март
  • Q2: апрель – июнь
  • Q3: июль – сентябрь
  • Q4: октябрь – декабрь

Метод возвращает первый день квартала в 00:00:00.000.


Иммутабельность результата

Любое применение startOf не изменяет исходный объект:

const original = DateTime.local(2026, 5, 23, 18, 45);
const normalized = original.startOf("day");

После выполнения:

  • original сохраняет исходное значение
  • normalized содержит обнулённое время

Это позволяет безопасно строить цепочки трансформаций без побочных эффектов.


Использование в цепочках

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

const result = DateTime.local()
  .plus({ days: 3 })
  .startOf("day")
  .minus({ hours: 5 });

Порядок операций имеет значение:

  1. сначала происходит сдвиг даты
  2. затем нормализация к началу дня
  3. затем корректировка времени

Взаимодействие с часовыми поясами

startOf работает в контексте текущего часового пояса объекта DateTime.

const dt = DateTime.now().setZone("Europe/Paris");
const start = dt.startOf("day");

Результат будет соответствовать полуночи именно в указанной зоне.

Важно учитывать переходы на летнее и зимнее время:

  • в дни с DST-переходом сутки могут быть не 24 часа
  • Luxon корректно пересчитывает локальное начало дня в рамках правил зоны

Пограничные случаи и особенности

Переходы времени (DST)

В дни смены времени:

  • «00:00» может существовать неявно или сдвигаться
  • startOf("day") возвращает корректный локальный момент, даже если он не совпадает с UTC-границей

Неверные значения unit

При передаче неподдерживаемого значения:

dt.startOf("century");

поведение зависит от версии, но обычно приводит к ошибке диапазона (RangeError) или возвращению невалидного DateTime. Использование строго ограниченного набора единиц считается обязательным.


Отличие от округления

startOf не выполняет математическое округление в привычном смысле. Он не анализирует «ближе к началу или концу», а всегда сдвигает вниз:

  • 18:59 → 18:00 при "hour"
  • 23:59 → 00:00 только при переходе к "day"

Это делает метод детерминированным и удобным для построения диапазонов.


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

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

const start = DateTime.local().startOf("month");
const end = DateTime.local().endOf("month");

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


Группировка событий

const key = eventDate.startOf("day").toISODate();

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


Построение календарей

const firstVisible = month.startOf("month").startOf("week");

Часто используется для построения сеток календаря, где отображаются неполные недели.


Поведение с миллисекундами

dt.startOf("millisecond");

Фактически возвращает тот же момент времени, но в нормализованной форме объекта. Полезность этого режима минимальна, однако он присутствует для симметрии API.


Связь с endOf

Метод часто используется совместно с endOf(unit):

  • startOf("day") → начало суток
  • endOf("day") → конец суток

Вместе они формируют строгие диапазоны включительно-исключающего типа или инклюзивного интервала в зависимости от логики приложения.


Поведение при работе с ISO-датами

При создании из ISO:

DateTime.fromISO("2026-05-23T18:45:00")

startOf работает одинаково, независимо от источника данных (ISO, JS Date, timestamp). Все преобразуется к единой внутренней модели Luxon перед применением операции.


Влияние локали

Локаль влияет главным образом на:

  • начало недели
  • календарные правила

Пример:

DateTime.local().setLocale("en-gb").startOf("week");

и

DateTime.local().setLocale("en-us").startOf("week");

могут давать разные результаты при одном и том же календарном дне.


Итоговое поведение как концепция

startOf в Luxon представляет собой механизм приведения времени к нижней границе выбранного временного интервала с учётом:

  • локали
  • часового пояса
  • календарной системы
  • DST-правил

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