Год, месяц, день

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

Создание даты с календарными компонентами

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

Основной способ — DateTime.local():

import { DateTime } from "luxon";

const dt = DateTime.local(2026, 5, 23);

Порядок аргументов строго фиксирован:

  • год
  • месяц (1–12)
  • день (1–31)

Месяцы в Luxon нумеруются с 1, а не с 0, как в стандартном JavaScript Date. Это устраняет типичную ошибку смещения индексов месяцев.

Создание даты через объект:

const dt = DateTime.local({
  year: 2026,
  month: 5,
  day: 23
});

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

Получение компонентов даты

Объект DateTime предоставляет прямой доступ к календарным частям:

const dt = DateTime.local(2026, 5, 23);

dt.year;  // 2026
dt.month; // 5
dt.day;   // 23

Эти свойства являются вычисляемыми и не изменяют объект.

Дополнительно доступны производные компоненты:

dt.weekday; // день недели (1 — понедельник, 7 — воскресенье)
dt.ordinal; // порядковый день года (1–365/366)
dt.weekNumber;

Изменение года, месяца и дня через set()

Для изменения отдельных частей даты используется метод set().

const dt = DateTime.local(2026, 5, 23);

const upd ated = dt.se t({
  year: 2027,
  month: 1,
  day: 10
});

Важно учитывать:

  • исходный объект не изменяется
  • возвращается новый DateTime
  • можно изменять только часть полей

Частичное обновление:

const nextMonth = dt.set({ month: 6 });
const nextYear = dt.set({ year: 2027 });

Нормализация даты и переполнение значений

Luxon автоматически нормализует некорректные календарные значения.

DateTime.local(2026, 2, 31);

Результат будет приведён к корректной дате:

  • февраль 2026 не имеет 31 дня
  • дата будет перенесена в март

Такое поведение называется clamping / normalization и предотвращает получение невалидных дат.

Работа с началом и концом периода

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

Начало года, месяца, дня

const dt = DateTime.local(2026, 5, 23);

dt.startOf("year");  // 2026-01-01
dt.startOf("month"); // 2026-05-01
dt.startOf("day");   // 2026-05-23 00:00:00

Конец года, месяца, дня

dt.endOf("year");  // 2026-12-31 23:59:59.999
dt.endOf("month"); // 2026-05-31 23:59:59.999
dt.endOf("day");   // 2026-05-23 23:59:59.999

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

Извлечение даты из ISO-строки

Luxon корректно парсит ISO 8601, сохраняя календарную структуру:

const dt = DateTime.fromISO("2026-05-23");

После парсинга доступны те же поля:

dt.year;  // 2026
dt.month; // 5
dt.day;   // 23

Если строка содержит только дату без времени, время устанавливается в 00:00:00.

Форматирование года, месяца и дня

Метод toFormat() используется для получения строкового представления.

const dt = DateTime.local(2026, 5, 23);

dt.toFormat("yyyy");     // "2026"
dt.toFormat("MM");       // "05"
dt.toFormat("dd");       // "23"
dt.toFormat("yyyy-MM-dd"); // "2026-05-23"

Основные токены:

  • yyyy — год
  • MM — месяц с ведущим нулём
  • M — месяц без ведущего нуля
  • dd — день с ведущим нулём
  • d — день без ведущего нуля

Разница между calendar components и timestamp

Luxon разделяет календарные компоненты и абсолютное время.

const dt = DateTime.local(2026, 5, 23);

Этот объект одновременно содержит:

  • календарную дату (year, month, day)
  • временную метку (timestamp)

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

Особенности месяцев и дней

Месяцы

  • диапазон: 1–12
  • январь = 1
  • декабрь = 12
DateTime.local(2026, 1, 1); // январь

Дни месяца

Количество дней зависит от месяца и високосного года.

DateTime.local(2024, 2, 29); // корректно (високосный год)
DateTime.local(2026, 2, 29); // будет нормализовано

Luxon учитывает календарную систему Gregorian.

Клонирование через изменение компонентов

Любая операция изменения года, месяца или дня фактически создаёт новый объект:

const base = DateTime.local(2026, 5, 23);

const a = base.set({ year: 2027 });
const b = base.set({ month: 6 });
const c = base.set({ day: 1 });

Все три результата независимы друг от друга и от base.

Работа с началом месяца через year/month/day

Комбинация startOf("month") и явной установки компонентов даёт эквивалентный результат:

const dt = DateTime.local(2026, 5, 23);

const start1 = dt.startOf("month");
const start2 = dt.set({ day: 1, hour: 0, minute: 0, second: 0, millisecond: 0 });

Разница заключается в уровне абстракции: startOf() работает декларативно, set() — явно.

Сравнение дат по календарным компонентам

Luxon позволяет сравнивать даты напрямую:

const a = DateTime.local(2026, 5, 10);
const b = DateTime.local(2026, 5, 23);

a < b; // true

Сравнение основано на timestamp, но при равенстве календарных частей оно эквивалентно сравнению year/month/day.

Перенос дат при изменении месяца

Особенность, связанная с длиной месяцев:

DateTime.local(2026, 1, 31).set({ month: 2 });

Результат:

  • февраль не содержит 31 дня
  • Luxon корректирует дату до последнего допустимого дня месяца

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

Изоляция календарных операций

Все операции с годом, месяцем и днём в Luxon изолированы:

  • нет мутации исходного объекта
  • нет скрытых глобальных изменений
  • каждый вызов возвращает новый DateTime
const original = DateTime.local(2026, 5, 23);

const modified = original.set({ day: 1 });

original.day;  // 23
modified.day;  // 1

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

Методы можно комбинировать:

const dt = DateTime.local()
  .set({ year: 2026 })
  .set({ month: 5 })
  .set({ day: 23 })
  .startOf("day");

Цепочки особенно полезны при формировании дат из разрозненных данных.

Граничные значения и безопасность дат

Luxon защищает от некорректных календарных состояний:

  • 13 месяц автоматически нормализуется
  • 0 день переносится в предыдущий месяц
  • отрицательные значения интерпретируются как сдвиги назад
DateTime.local(2026, 0, 10); // декабрь предыдущего года

Такое поведение делает работу с календарём устойчивой к ошибкам входных данных.

Календарные компоненты и локализация

Хотя year/month/day универсальны, их отображение зависит от локали при форматировании:

dt.setLocale("ru").toLocaleString(DateTime.DATE_FULL);

Календарная структура остаётся неизменной, изменяется только представление.

Работа с минимальными и максимальными значениями месяца

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

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

Эти значения используются для:

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

Влияние временной зоны на календарные поля

Год, месяц и день зависят от текущей зоны:

const dt = DateTime.local().setZone("Asia/Almaty");

Изменение зоны может привести к изменению календарного дня, если момент времени пересекает границу суток в новой зоне.

Конвертация между календарными представлениями

Luxon позволяет легко переходить между разными уровнями детализации:

const dt = DateTime.local(2026, 5, 23);

dt.toISODate(); // "2026-05-23"
dt.toISO();     // полная дата и время

Календарные компоненты сохраняются во всех представлениях ISO.

Практика устойчивого формирования дат

При построении дат из пользовательского ввода используется строгая сборка:

function buildDate(y, m, d) {
  return DateTime.local(y, m, d).startOf("day");
}

Такой подход фиксирует:

  • календарную точку
  • начало суток
  • отсутствие случайных временных значений