Settings.throwOnInvalid

Назначение настройки

Settings.throwOnInvalid управляет стратегией обработки некорректных значений времени в Luxon. Речь идёт о ситуации, когда создаётся или преобразуется объект DateTime, но входные данные не могут быть интерпретированы как валидная дата.

В обычном режиме Luxon не прерывает выполнение программы при ошибке парсинга. Вместо этого возвращается объект DateTime, помеченный как невалидный. При включении throwOnInvalid поведение становится строгим: вместо объекта с состоянием ошибки выбрасывается исключение.

Ключевая идея настройки:

  • false (значение по умолчанию): ошибки представлены через объект DateTime с состоянием invalid
  • true: ошибки приводят к немедленному выбросу исключения

Базовая модель невалидного DateTime

При стандартной конфигурации:

import { DateTime } from "luxon";

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

console.log(dt.isValid); // false
console.log(dt.invalidReason); // объяснение причины
console.log(dt.invalidExplanation); // детальное описание

Объект при этом остаётся экземпляром DateTime, что позволяет продолжать цепочки вызовов, но любые операции будут возвращать невалидные результаты.


Включение строгого режима

Настройка изменяется через глобальный объект Settings:

import { Settings, DateTime } from "luxon";

Settings.throwOnInvalid = true;

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

В этом режиме выполнение кода прерывается исключением:

RangeError: Invalid DateTime

или более детализированным сообщением в зависимости от источника ошибки.


Поведение при различных источниках данных

ISO-строки
Settings.throwOnInvalid = true;

DateTime.fromISO("2024-13-40");

Любое нарушение формата или логики календаря приводит к исключению. Например:

  • месяц 13
  • день 40
  • некорректный формат строки

Форматированные строки
DateTime.fromFormat("32/01/2024", "dd/MM/yyyy");

Если вход не соответствует формату, происходит выброс ошибки, а не возврат невалидного объекта.


Unix timestamp
DateTime.fromMillis(NaN);

или

DateTime.fromSeconds("abc");

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


Отличие моделей обработки ошибок

Мягкий режим (по умолчанию)
  • Ошибка кодируется внутри объекта
  • Выполнение программы продолжается
  • Проверка требует isValid
const dt = DateTime.fromISO("invalid");

if (!dt.isValid) {
  console.log(dt.invalidReason);
}
Строгий режим
  • Ошибка превращается в исключение
  • Обработка через try/catch
  • Нет возможности получить объект DateTime в невалидном состоянии
try {
  const dt = DateTime.fromISO("invalid");
} catch (e) {
  console.log("Ошибка парсинга даты");
}

Влияние на цепочки вызовов

В Luxon часто используются цепочки преобразований:

DateTime.fromISO("2024-01-01")
  .plus({ days: 5 })
  .setZone("Europe/Paris")
  .toISO();

При throwOnInvalid = true ошибка в любом промежуточном этапе разрывает цепочку мгновенно. При выключенной настройке ошибка может оставаться скрытой до момента использования результата.


Практическая семантика invalid объекта

При стандартном режиме:

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

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

Invalid объект сохраняет структуру:

  • содержит поле причины invalidReason
  • содержит описание invalidExplanation
  • сохраняет исходные входные данные

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


Сценарии применения throwOnInvalid

Строгая валидация входных данных

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

  • финансовые системы
  • планировщики задач
  • интеграции с API, где ошибка данных критична
Settings.throwOnInvalid = true;

function parseEvent(dateStr) {
  return DateTime.fromISO(dateStr);
}

Любая ошибка превращается в исключение, что позволяет централизованно обрабатывать сбои.


Тестируемые вычисления

В тестовой среде строгий режим позволяет выявлять ошибки сразу:

beforeAll(() => {
  Settings.throwOnInvalid = true;
});

Это предотвращает ситуацию, когда тесты проходят с невалидными объектами.


API-слой приложения

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

app.post("/event", (req, res) => {
  try {
    const dt = DateTime.fromISO(req.body.date);
    res.send({ ok: true });
  } catch {
    res.status(400).send({ error: "invalid date" });
  }
});

Глобальность настройки

Settings.throwOnInvalid является глобальной настройкой для всего процесса выполнения JavaScript.

Это означает:

  • изменение влияет на все последующие операции Luxon
  • настройка не ограничена одним модулем
  • легко создать скрытые побочные эффекты
Settings.throwOnInvalid = true;

// в другом модуле
DateTime.fromISO("bad"); // уже кидает исключение

Риски глобального переключения

Строгий режим может приводить к трудноуловимым проблемам:

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

Особенно критично при:

  • серверных приложениях с множеством модулей
  • shared runtime (например, serverless функции с общими зависимостями)

Рекомендуемые модели использования

Часто используется динамическое переключение:

const previous = Settings.throwOnInvalid;

Settings.throwOnInvalid = true;

try {
  const dt = DateTime.fromISO(input);
} finally {
  Settings.throwOnInvalid = previous;
}

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


Взаимодействие с другими настройками

Luxon имеет набор глобальных настроек, и throwOnInvalid взаимодействует с ними косвенно:

  • локаль (locale) не влияет на факт валидности
  • таймзоны (zone) не исправляют некорректные значения
  • форматирование не предотвращает исключения при парсинге

Ошибка возникает до этапа форматирования или вычислений.


Поведение в цепочках преобразований

Пример цепочки:

DateTime.fromISO("2024-01-01")
  .plus({ days: 10 })
  .setZone("invalid-zone")
  .toISO();

В строгом режиме ошибка зоны приведёт к немедленному исключению на этапе setZone.

В мягком режиме может появиться invalid DateTime, который распространяется дальше по цепочке.


Различие между исключением и invalid-объектом

Поведение throwOnInvalid = false throwOnInvalid = true
Парсинг ошибки возвращается invalid DateTime выбрасывается исключение
Проверка через isValid через try/catch
Цепочки продолжаются с invalid состоянием прерываются
Диагностика постфактум мгновенная

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

Отсутствие восстановления настройки
Settings.throwOnInvalid = true;
// забыто вернуть обратно

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


Ожидание поведения как у валидатора

Некорректное предположение:

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

Смешивание режимов

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

  • один код проверяет isValid
  • другой использует try/catch

Это создаёт несогласованность архитектуры обработки времени.


Роль настройки в архитектуре приложений

Settings.throwOnInvalid фактически определяет стиль работы с датами:

  • декларативная модель (invalid-объекты)
  • исключительная модель (exceptions)

Выбор влияет на:

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