Типичные ошибки

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

Типичная ошибка проявляется при цепочках вызовов:

let dt = DateTime.now();
dt.plus({ days: 2 });
dt.minus({ hours: 3 });

console.log(dt.toString());

В результате выводится исходное значение, поскольку результаты plus и minus были проигнорированы. Правильный подход требует явного сохранения возвращаемого значения:

let dt = DateTime.now()
  .plus({ days: 2 })
  .minus({ hours: 3 });

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


Неправильная работа с часовыми поясами

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

const dt = DateTime.fromISO("2024-01-01T10:00", { zone: "utc" });
const shifted = dt.setZone("Asia/Almaty");

setZone не изменяет момент времени, а лишь отображение. Это означает, что 10:00 UTC станет другим локальным временем в новой зоне, но момент времени останется тем же.

Частая ошибка — ожидание смещения времени как арифметической операции:

dt.setZone("Asia/Almaty").hour // не "пересчитывает" время как прибавление смещения

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


Путаница между DateTime, Duration и Interval

Luxon разделяет три сущности:

  • DateTime — точка во времени
  • Duration — длительность
  • Interval — промежуток между двумя точками

Распространённая ошибка — использование Duration как DateTime:

const d = Duration.fromObject({ hours: 2 });
console.log(d.plus({ hours: 1 }));

Хотя это допустимо, результат остаётся длительностью, а не временем.

Ещё более критичная ошибка — попытка сравнивать Interval как дату:

const i = Interval.fromDateTimes(dt1, dt2);
console.log(i > DateTime.now());

Сравнение не имеет смысла и приводит к логическим сбоям. Правильный подход — использовать методы overlaps, contains, isAfter, isBefore.


Ошибки парсинга ISO и нестандартных форматов

Luxon строго различает методы парсинга. Частая ошибка — использование fromISO для не-ISO строк:

DateTime.fromISO("01-02-2024");

Такая строка не соответствует ISO-формату и вернёт Invalid DateTime.

Для произвольных форматов требуется fromFormat:

DateTime.fromFormat("01-02-2024", "dd-MM-yyyy");

Ошибка в маске форматирования приводит к тихой невалидности объекта, что часто не проверяется:

const dt = DateTime.fromFormat("2024/01/01", "dd-MM-yyyy");
console.log(dt.isValid); // false

Игнорирование isValid — одна из самых распространённых причин скрытых багов.


Игнорирование проверки isValid

Каждый объект Luxon может оказаться невалидным. Ошибка часто возникает при цепочках:

const dt = DateTime.fromFormat(input, "yyyy-MM-dd")
  .plus({ days: 1 });

Если input некорректен, дальнейшие операции сохраняют невалидное состояние.

Правильная практика — проверка после парсинга:

const dt = DateTime.fromFormat(input, "yyyy-MM-dd");

if (!dt.isValid) {
  // обработка ошибки
}

Отсутствие проверки приводит к распространению Invalid DateTime по всей логике приложения.


Ошибки при форматировании строк

Метод toFormat использует собственный синтаксис токенов, отличный от Intl и Moment.js. Частая ошибка — использование неправильных символов:

dt.toFormat("YYYY-MM-DD"); // неправильно

В Luxon корректный вариант:

dt.toFormat("yyyy-MM-dd");

Различие между yyyy и YYYY критично: первое — календарный год, второе — ISO-неделя, что приводит к ошибкам в конце года.


Неправильное использование toLocaleString

Метод toLocaleString опирается на встроенные пресеты, и попытка передать кастомный формат приводит к неожиданным результатам:

dt.toLocaleString(DateTime.DATE_HUGE);

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

Для точного форматирования необходимо использовать toFormat.


Проблемы с переходом на JavaScript Date

При конвертации через toJSDate теряется информация о временной зоне Luxon:

const jsDate = dt.toJSDate();

Date хранит момент времени в UTC, но не сохраняет оригинальную зону Luxon. При обратном преобразовании зона не восстанавливается:

DateTime.fromJSDate(jsDate).zoneName; // системная зона

Это приводит к ошибкам при многозонной логике.


Ошибки работы с UTC и локальным временем

Частая ошибка — смешивание local и utc без явного контроля:

const dt = DateTime.local().toUTC();

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

dt.toLocal(); // зависит от системной зоны

В распределённых системах это приводит к различиям между окружениями.


Некорректное использование startOf и endOf

Методы startOf и endOf возвращают новые объекты, а также изменяют только указанный уровень точности.

Ошибка возникает при ожидании полного «обнуления» времени:

dt.startOf("day");

Результат будет иметь 00:00, но зона и момент времени сохраняются.

Частая проблема — сравнение таких значений без учёта зоны:

dt.startOf("day") === otherDate.startOf("day");

Сравнение объектов всегда по ссылке, а не по значению.


Ошибки при работе с длительностями и сложением единиц

Luxon допускает сложение объектов, но неправильное использование приводит к логическим дефектам:

DateTime.now().plus({ months: 1, days: 30 });

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


Проблемы с таймзонными идентификаторами

Некорректные строки зон не всегда вызывают очевидную ошибку:

DateTime.now().setZone("Asia/Alma-Ata");

Если идентификатор не поддерживается, Luxon может вернуть невалидное состояние или fallback-зону. Это особенно критично при миграции между библиотеками и базами данных.


Потеря точности при миллисекундах и округлениях

Luxon хранит время с точностью до миллисекунд, но форматирование может скрывать эту точность:

dt.toFormat("HH:mm:ss");

Миллисекунды теряются визуально, но сохраняются в объекте, что приводит к расхождению при сравнении:

dt1.equals(dt2); // может быть false при одинаковом отображении

Ошибки при сериализации и хранении

Часто DateTime сериализуют напрямую:

JSON.stringify(dt);

Результат не содержит полезной структуры Luxon. Правильный подход — явное преобразование:

dt.toISO();

Игнорирование этого приводит к потере зоны, точности и контекста времени при передаче между сервисами.