DateTimeException и его производные

В библиотеке js-joda ошибки, связанные с работой даты и времени, централизованы вокруг базового типа DateTimeException. Он используется как корневой класс для большинства ошибок, возникающих при парсинге, преобразованиях, вычислениях и работе с календарными системами. Такая структура повторяет подход Java Time API, на котором основана библиотека.

Иерархия упрощённо выглядит так:

  • DateTimeException

    • DateTimeParseException
    • ZoneRulesException
    • UnsupportedTemporalTypeException (в отдельных реализациях/портированных частях API)
  • отдельные runtime-исключения, связанные с переполнением (например, ArithmeticException)


DateTimeException как базовое исключение

DateTimeException является корневым классом для всех специфичных ошибок временной модели. Он представляет собой unchecked-исключение, что означает отсутствие обязательной обработки через try/catch, хотя в прикладном коде обработка часто необходима.

Основные сценарии возникновения:

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

Пример возникновения базовой ошибки:

import { LocalDate } from '@js-joda/core';

const date = LocalDate.of(2024, 2, 30);

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


Природа ошибок времени в js-joda

Особенность временной модели заключается в строгой валидации каждого компонента:

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

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

Пример:

import { LocalTime } from '@js-joda/core';

const time = LocalTime.of(25, 10);

Здесь значение часа выходит за пределы диапазона 0–23, что приводит к DateTimeException.


DateTimeParseException

Одним из наиболее частых наследников DateTimeException является DateTimeParseException. Оно возникает при попытке преобразовать строку в объект даты/времени, если формат не соответствует ожидаемому шаблону.

Причины возникновения

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

Пример ошибки парсинга

import { LocalDate } from '@js-joda/core';

const date = LocalDate.parse('2024-13-10');

Месяц 13 не существует, поэтому парсер выбрасывает DateTimeParseException.

Типичная структура исключения

DateTimeParseException обычно содержит:

  • входную строку
  • индекс ошибки (позицию, где произошёл сбой)
  • сообщение о причине

Это делает его более информативным по сравнению с базовым DateTimeException.

Пример с пользовательским форматом

import { DateTimeFormatter, LocalDate } from '@js-joda/core';

const formatter = DateTimeFormatter.ofPattern('yyyy/MM/dd');

const date = LocalDate.parse('2024-02-30', formatter);

Здесь ошибка возникает не из-за формата, а из-за несуществующей даты, но тип исключения остаётся тем же.


ZoneRulesException

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

Основные причины

  • неизвестный идентификатор зоны
  • отсутствие правил перехода на летнее/зимнее время
  • повреждённые или некорректные данные временной зоны
  • попытка использования несуществующей зоны

Пример

import { ZoneId } from '@js-joda/core';

const zone = ZoneId.of('Mars/Phobos');

Такой идентификатор не существует в базе временных зон, что приводит к ZoneRulesException.

Особенности поведения

Ошибки зон часто связаны не с кодом, а с окружением:

  • урезанные базы IANA
  • устаревшие данные временных зон
  • кастомные сборки js-joda без полной базы правил

UnsupportedTemporalTypeException

Это исключение возникает при попытке использовать временное поле или операцию, которая не поддерживается конкретным типом даты/времени.

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

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

Пример

import { LocalDate } from '@js-joda/core';

const date = LocalDate.now();

date.getHour();

LocalDate не содержит информации о времени суток, поэтому доступ к getHour() приводит к UnsupportedTemporalTypeException.

Логика возникновения

Каждый временной тип в js-joda реализует ограниченный набор полей:

  • LocalDate — только дата
  • LocalTime — только время
  • LocalDateTime — дата и время
  • ZonedDateTime — дата, время и зона

Попытка выйти за рамки модели приводит к исключению.


ArithmeticException в контексте временных операций

Хотя ArithmeticException не является прямым наследником DateTimeException, он тесно связан с временными вычислениями.

Основная причина

  • переполнение при сложении или вычитании временных значений

Пример переполнения

import { LocalDate } from '@js-joda/core';

const date = LocalDate.of(999999999, 1, 1);
const result = date.plusYears(1);

Если результат выходит за пределы допустимого диапазона, возникает ArithmeticException.

Особенности

  • не относится строго к календарной логике
  • связан с числовыми ограничениями JavaScript/реализации
  • часто возникает при больших сдвигах времени

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

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

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

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

Иммутабельность объектов

Все объекты js-joda неизменяемы. Это приводит к тому, что:

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

Явная модель времени

В отличие от Date в JavaScript, js-joda не допускает:

  • невалидных дат
  • скрытых преобразований
  • автоматической нормализации некорректных значений

Ошибки преобразования между типами

Частый источник исключений — преобразования между временными сущностями:

  • LocalDateZonedDateTime
  • InstantLocalDate без зоны
  • строки → временные объекты

Пример:

import { Instant, LocalDate } from '@js-joda/core';

const instant = Instant.now();
const date = LocalDate.from(instant);

Такое преобразование требует контекста временной зоны. При его отсутствии возникает DateTimeException.


Поведение при некорректных цепочках операций

В цепочках вызовов ошибка может возникнуть на любом этапе:

import { LocalDate } from '@js-joda/core';

const result = LocalDate.of(2024, 2, 28)
  .plusDays(1)
  .plusMonths(1)
  .withDayOfMonth(31);

Если конечная операция приводит к несуществующей дате (например, 31 марта → 31 апреля), выбрасывается DateTimeException.


Диагностика причин исключений

При анализе ошибок временной модели важны:

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

Особенно важно учитывать, что js-joda не скрывает ошибки через автокоррекцию, а фиксирует их строго через исключения.


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

Парсинг и форматирование используют единый механизм:

  • форматтер определяет структуру
  • парсер проверяет соответствие
  • несоответствие приводит к DateTimeParseException

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

import { DateTimeFormatter, LocalDate } from '@js-joda/core';

const formatter = DateTimeFormatter.ofPattern('dd-MM-yyyy');

LocalDate.parse('31-02-2024', formatter);

Ошибка возникает на этапе валидации календаря, а не синтаксиса строки.