Обработка невалидных объектов

В библиотеке Luxon любой результат работы с датами, интервалами и длительностями может находиться в состоянии валидности или невалидности. Это ключевой механизм защиты от некорректных вычислений: вместо выброса исключений большинство методов возвращают объект, который явно помечен как невалидный.

Невалидный объект — это экземпляр DateTime, Duration или Interval, который не смог быть корректно создан или преобразован из входных данных. При этом он сохраняет интерфейс объекта библиотеки, но любые операции над ним либо возвращают другие невалидные объекты, либо становятся бессмысленными.


Основные причины появления невалидных объектов

Некорректный парсинг строк

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

import { DateTime } from "luxon";

const dt = DateTime.fromISO("2026-13-40");

console.log(dt.isValid); // false

Здесь строка не соответствует ISO-формату: месяц 13 и день 40 не существуют.


Несоответствие формата при fromFormat

При ручном разборе дат через шаблон ошибки возникают особенно часто:

const dt = DateTime.fromFormat("31/02/2026", "dd/MM/yyyy");

console.log(dt.isValid); // false
console.log(dt.invalidReason); // 'unparsable'

Даже если строка формально соответствует шаблону, логическая корректность (например, существование 31 февраля) всё равно проверяется.


Ошибки таймзоны

Некорректное имя зоны приводит к невалидности:

const dt = DateTime.now().setZone("Mars/Phobos");

console.log(dt.isValid); // false
console.log(dt.invalidReason); // 'unsupported zone'

Luxon опирается на IANA Time Zone Database, и любое отклонение от допустимых значений делает объект невалидным.


Ошибки при создании из некорректных значений

const dt = DateTime.fromObject({
  year: 2026,
  month: 2,
  day: 30
});

console.log(dt.isValid); // false

Любые невозможные календарные комбинации приводят к невалидному результату.


Свойства, определяющие состояние валидности

isValid

Главный индикатор состояния объекта:

if (!dt.isValid) {
  // объект нельзя использовать для вычислений
}

Это первое, что проверяется перед любыми операциями.


invalidReason

Строковое описание причины:

  • "unparsable" — строка не распознана
  • "unit out of range" — значение выходит за допустимые пределы
  • "unsupported zone" — таймзона не существует
  • "invalid input" — общий случай некорректных данных
console.log(dt.invalidReason);

invalidExplanation

Более подробное объяснение причины, часто полезное при отладке:

console.log(dt.invalidExplanation);

Пример вывода может содержать указание на конкретный компонент, который вызвал сбой.


Поведение методов при невалидных объектах

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

const dt = DateTime.fromISO("invalid-date");

const shifted = dt.plus({ days: 5 });

console.log(shifted.isValid); // false

Библиотека не пытается «исправлять» уже сломанные данные.


Невалидные Duration

Аналогичная модель применяется к длительностям:

import { Duration } from "luxon";

const d = Duration.fromObject({ hours: "ten" });

console.log(d.isValid); // false
console.log(d.invalidReason); // 'invalid input'

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


Невалидные Interval

Интервалы требуют корректных границ:

import { Interval, DateTime } from "luxon";

const start = DateTime.fromISO("2026-01-10");
const end = DateTime.fromISO("2026-01-01");

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

console.log(interval.isValid); // false

Если начало позже конца — объект считается некорректным.


Особенности цепочек вызовов

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

const dt = DateTime.fromISO("invalid")
  .setZone("UTC")
  .plus({ days: 1 })
  .setLocale("ru");

console.log(dt.isValid); // false

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


Проверка валидности перед форматированием

Форматирование не исправляет ошибки:

const dt = DateTime.fromISO("bad input");

console.log(dt.toISO());      // null
console.log(dt.toString());   // "Invalid DateTime"

Без проверки isValid можно получить неожиданные строки или null.


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

1. Данные из API

const dt = DateTime.fromISO(apiResponse.date);
if (!dt.isValid) {
  // защита от некорректного сервера
}

2. Пользовательский ввод

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

if (!dt.isValid) {
  console.log(dt.invalidExplanation);
}

3. Смешанные форматы

const dt = DateTime.fromISO("2026/01/01"); // неверный ISO

console.log(dt.isValid); // false

Стратегии обработки невалидных объектов

Явная проверка перед использованием

function safeFormat(dt) {
  if (!dt.isValid) return "Некорректная дата";
  return dt.toFormat("dd LLL yyyy");
}

Замена на дефолтное значение

const dt = DateTime.fromISO(input);

const safe = dt.isValid ? dt : DateTime.now();

Логирование причины ошибки

if (!dt.isValid) {
  console.error(dt.invalidReason, dt.invalidExplanation);
}

Важное поведение при сериализации

Невалидные объекты при преобразовании в JSON теряют полезные данные:

const dt = DateTime.fromISO("bad");

console.log(JSON.stringify(dt)); 
// {}

Это связано с тем, что внутреннее состояние считается недостоверным.


Отличие от выбрасывания исключений

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

  • нет необходимости в try/catch для обычного парсинга
  • ошибки выражаются через состояние объекта
  • обработка унифицирована через isValid

Поведение в вычислениях с таймзонами и локалями

Некорректные локали обычно не делают объект невалидным, но могут приводить к неожиданным форматам. Таймзоны же строго валидируются:

const dt = DateTime.now().setZone("invalid-zone");

console.log(dt.isValid); // false

Практическая модель проверки

Устойчивый шаблон работы:

const dt = DateTime.fromISO(input);

if (!dt.isValid) {
  return handleError(dt.invalidReason);
}

return dt.toUTC().toISO();

Распространённые ошибки разработчиков

  • использование toISO() без проверки isValid
  • игнорирование invalidReason
  • попытка «исправить» объект через последующие методы
  • предположение, что библиотека выбрасывает исключения

Поведение при смешанных операциях

const dt = DateTime.fromISO("invalid")
  .toUTC()
  .set({ hour: 10 });

console.log(dt.isValid); // false

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


Контроль целостности данных в сложных сценариях

При работе с цепочками преобразований важна централизованная проверка:

function transformDate(input) {
  const dt = DateTime.fromISO(input);

  if (!dt.isValid) return null;

  return dt
    .setZone("UTC")
    .startOf("day")
    .toISO();
}

Такой подход предотвращает распространение невалидных объектов по системе.