ResolverStyle и его влияние

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

Общая роль ResolverStyle

ResolverStyle определяет, как именно библиотека должна интерпретировать входные данные при преобразовании строк или наборов полей в объекты даты и времени (LocalDate, LocalDateTime, ZonedDateTime и др.).

Он применяется в момент “разрешения” полей после их извлечения из строки через DateTimeFormatter. На этом этапе система уже имеет набор числовых значений (год, месяц, день, час и т.д.), но ещё не решила, являются ли они корректной календарной комбинацией.

Основная задача ResolverStyle — определить поведение при:

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

Доступные режимы ResolverStyle

В js-joda выделяются три основных стратегии:

STRICT

Строгий режим, при котором любые отклонения от календарной корректности приводят к ошибке.

Характеристики:

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

Пример поведения:

  • 2021-02-30 → ошибка (февраль не имеет 30 дней)
  • 2021-04-31 → ошибка (апрель имеет 30 дней)
  • 2020-02-29 → допустимо (високосный год)

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


SMART

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

Характеристики:

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

Примеры поведения:

  • 2021-02-302021-02-28 (последний день месяца)
  • 2021-04-312021-04-30
  • 2021-01-32 → ошибка или корректировка в зависимости от контекста полей (обычно ограничение до конца месяца, без перехода в следующий)

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


LENIENT

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

Характеристики:

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

Примеры поведения:

  • 2021-01-322021-02-01
  • 2021-12-402022-01-09
  • 2021-02-60 → перенос в март

LENIENT фактически рассматривает дату как набор чисел, которые нормализуются в календарную форму.


Влияние ResolverStyle на DateTimeFormatter

ResolverStyle применяется через конфигурацию форматтера:

DateTimeFormatter
  .ofPattern("yyyy-MM-dd")
  .withResolverStyle(ResolverStyle.STRICT);

Именно на этапе вызова parse() происходит применение выбранной стратегии.

Разница особенно заметна при одинаковом шаблоне форматирования, но разных стилях разрешения.

Пример различий

Входная строка: 2021-02-31

  • STRICT → ошибка парсинга
  • SMART → 2021-02-28
  • LENIENT → переход к 2021-03-03

Влияние на локальные и составные типы дат

LocalDate

Наиболее чувствителен к ResolverStyle, так как полностью зависит от календарной валидности.

  • STRICT полностью запрещает невалидные даты
  • SMART корректирует день месяца
  • LENIENT позволяет календарным переполнениям менять месяц и год

LocalDateTime

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

  • переполнение дней влияет на дату
  • переполнение часов влияет на дни

Пример:

  • 2021-01-01T25:00 в LENIENT → 2021-01-02T01:00

SMART обычно ограничивает подобные случаи более консервативно.


ZonedDateTime

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

  • корректировка даты может изменять локальное время переходов DST
  • STRICT предотвращает неконсистентные комбинации даты и зоны

Работа с DateTimeFormatterBuilder

При построении сложных форматтеров ResolverStyle влияет на интерпретацию полей, собранных из разных источников:

  • appendValue() без ограничений может создавать неоднозначные значения
  • комбинации “год + день года” или “неделя + день недели” требуют разрешения конфликтов

Пример конфликтной ситуации:

  • год = 2021
  • день года = 400

Результат:

  • STRICT → ошибка
  • SMART → приведение к последнему дню года
  • LENIENT → перенос в следующий год

Обработка переполнений и нормализация

Переполнение месяцев

LENIENT допускает выход за пределы 1–12:

  • 13 месяц → январь следующего года
  • 0 месяц → декабрь предыдущего года

Переполнение дней

LENIENT перераспределяет дни по календарю:

  • 32 января → 1 февраля
  • 365+ день года → следующий год

SMART ограничивает переполнение в рамках месяца.

STRICT полностью запрещает такие значения.


Различия в стратегии валидации

Ситуация STRICT SMART LENIENT
31 апреля ошибка 30 апреля 1 мая
30 февраля ошибка 28/29 февраля март с переносом
32 января ошибка ошибка/ограничение 1 февраля
некорректный месяц ошибка корректировка перенос года

Практическое влияние на парсинг

Выбор ResolverStyle определяет не только поведение ошибок, но и саму семантику данных:

  • STRICT задаёт модель «календарь как правило»
  • SMART задаёт модель «календарь как интерфейс с автоисправлением»
  • LENIENT задаёт модель «календарь как числовая шкала времени»

Эти различия критичны при:

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

Влияние на неоднозначные поля

Некоторые комбинации полей не имеют единственного решения без стратегии разрешения:

  • день месяца + день года
  • год + неделя года + день недели
  • era + year

STRICT требует полной согласованности всех полей.

SMART выбирает наиболее логичное представление в пределах календаря.

LENIENT преобразует все значения в единую шкалу времени с последующей нормализацией.


Итоговая модель поведения ResolverStyle в js-joda

ResolverStyle формирует фундаментальный слой интерпретации дат, определяя границу между:

  • жёсткой календарной корректностью
  • адаптивной корректировкой ошибок
  • арифметической моделью времени

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