Обработка невалидных значений

Библиотека js-joda реализует строгую модель работы с датами и временем, заимствованную из Java Time API. Ключевой принцип заключается в том, что большинство операций с некорректными входными данными не приводят к «мягким» результатам или автоматическим исправлениям — вместо этого возбуждаются исключения. Это позволяет избегать скрытых ошибок и неоднозначных состояний времени.

Основные источники невалидных значений:

  • некорректные строки при парсинге ("2024-02-30", "not-a-date")
  • выход значений за допустимые диапазоны (например, переполнение Instant)
  • использование null или undefined
  • некорректные временные зоны
  • нарушение календарных правил (несуществующие даты)
  • попытка обращения к неподдерживаемым полям времени

Иерархия исключений и их семантика

DateTimeException

Базовое исключение для всех ошибок, связанных с датой и временем. В js-joda оно используется как универсальный сигнал о том, что операция невозможна из-за некорректного состояния данных.

Типичные ситуации:

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

Пример:

LocalDate.of(2023, 2, 30); // ошибка

Февраль не содержит 30 дней, поэтому выбрасывается исключение.


DateTimeParseException

Возникает при неудачном разборе строки даты или времени.

LocalDate.parse("2023-13-01");

Месяц 13 выходит за допустимый диапазон, поэтому парсер прерывает выполнение.

Особенность: ошибка возникает до создания объекта, на этапе синтаксического анализа строки.


NullPointerException

В js-joda используется для строгого контроля входных параметров. Любое значение null или undefined, переданное туда, где ожидается объект времени или числовой параметр, приводит к исключению.

LocalDate.of(null, 1, 10);

Даже если логически можно было бы «подставить текущее значение», библиотека этого не делает.


ArithmeticException

Возникает при переполнении или выходе числовых операций за допустимые границы, особенно при работе с Instant, Duration, Period.

Instant.ofEpochSecond(Number.MAX_SAFE_INTEGER * 10);

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

Особенности обработки null и undefined

JavaScript-специфика добавляет отдельный класс проблем, нехарактерных для Java:

  • undefined часто появляется при деструктуризации
  • null передаётся как результат отсутствующих данных из API
  • отсутствие строгой типизации входных параметров

js-joda не выполняет автоматическое приведение типов, поэтому любое «пустое» значение считается ошибкой.

LocalDate.of(undefined, 5, 10); // NullPointerException

Ключевой принцип: отсутствие значения не интерпретируется как «сегодня» или «минимальная дата».

Ошибки при парсинге строковых представлений

Неверный формат строки

Парсер ожидает строго определённые ISO-форматы:

  • YYYY-MM-DD для LocalDate
  • YYYY-MM-DDTHH:mm для LocalDateTime
  • YYYY-MM-DDTHH:mm:ssZ для Instant

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

LocalDate.parse("01-2024-12"); // DateTimeParseException

Логически некорректные значения

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

LocalDate.parse("2024-02-30");

Парсер не выполняет «исправление» даты на 28 или 29 февраля — операция считается ошибочной.

Строгая модель календаря

js-joda использует календарь, где каждая дата должна существовать в реальном григорианском календаре.

Невозможные комбинации:

  • 31 апреля
  • 30 февраля
  • 29 февраля в не високосный год
LocalDate.of(2023, 2, 29); // ошибка

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

Обработка временных зон

Невалидные идентификаторы ZoneId

ZoneId.of("Mars/Phobos");

Любая строка, не входящая в список IANA time zone database, вызывает исключение.

Типичная ошибка:

  • опечатки ("Europe/Moskow")
  • устаревшие идентификаторы
  • пользовательские строки вместо стандарта

Стратегия безопасного получения зон

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

Работа с диапазонами Instant

Instant опирается на эпоху Unix и имеет жесткие границы:

  • минимальное значение ограничено внутренним представлением
  • максимальное значение также ограничено безопасным диапазоном чисел JavaScript

Ошибки возникают при:

  • переполнении Number
  • попытке преобразовать некорректный timestamp
Instant.ofEpochMilli("abc"); // DateTimeException

Переполнение и потеря точности

JavaScript использует Number с ограниченной точностью, поэтому js-joda защищает операции от некорректных результатов:

  • сложение больших Duration
  • умножение интервалов
  • конвертация больших временных диапазонов

При выходе за пределы:

Duration.ofDays(1e15);

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

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

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

  • LocalDate не содержит часов
  • Instant не поддерживает месяцы
  • YearMonth не имеет дня

Попытка доступа к неподдерживаемому полю:

localDate.get(ChronoField.HOUR_OF_DAY);

вызывает ошибку DateTimeException.

Стратегии защиты от невалидных значений

Предварительная валидация входных данных

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

  • тип значения
  • диапазон чисел
  • формат строки
  • наличие обязательных полей
function safeLocalDate(year, month, day) {
  if (
    typeof year !== "number" ||
    typeof month !== "number" ||
    typeof day !== "number"
  ) {
    return null;
  }

  try {
    return LocalDate.of(year, month, day);
  } catch (e) {
    return null;
  }
}

Защитный парсинг строк

function safeParseDate(str) {
  try {
    return LocalDate.parse(str);
  } catch (e) {
    return null;
  }
}

Такая модель используется при работе с внешними API, где данные не гарантированно корректны.


Разделение слоёв валидации

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

  1. Синтаксическая проверка (формат строки)
  2. Семантическая проверка (существует ли дата)
  3. Доменные ограничения (например, дата не может быть в будущем)
  4. Создание объекта js-joda

Особенности работы с пользовательскими форматами

При использовании DateTimeFormatter ошибки могут возникать на нескольких этапах:

  • некорректный шаблон форматтера
  • несовпадение строки и шаблона
  • частично разобранные данные
DateTimeFormatter.ofPattern("dd-MM-yyyy").parse("2024/12/01");

Здесь ошибка возникает из-за несовпадения разделителей.

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

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

  • добавление месяцев к дате конца месяца
  • вычитание интервалов, приводящее к выходу за границы
  • локальные переходы времени (DST)
localDate.plusMonths(1).plusDays(31);

Если промежуточное значение становится невалидным, операция прерывается.

Защитные паттерны использования

Pattern: try-catch как слой доменной безопасности

function toInstant(value) {
  try {
    return Instant.parse(value);
  } catch {
    return null;
  }
}

Pattern: нормализация входных данных

Перед передачей в js-joda значения приводятся к:

  • числам (без строк)
  • ISO-форматам
  • UTC-зоне по умолчанию

Pattern: изоляция внешних данных

Все данные, приходящие извне (API, пользовательский ввод, база данных), считаются потенциально невалидными до проверки.

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

  • неконсистентные даты в JSON (строки вместо чисел)
  • неправильные часовые пояса от клиента
  • частично заполненные формы
  • устаревшие форматы хранения дат
  • миграции между библиотеками времени

Работа js-joda усиливает необходимость строгого контроля входных данных, поскольку библиотека не допускает неявных исправлений и всегда сигнализирует об ошибке через исключения.