Система единиц измерения времени

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


ChronoUnit представляет собой центральный механизм, описывающий единицы измерения времени от наносекунд до эпохальных интервалов. Каждая единица определяет два ключевых аспекта: возможность точного вычисления разницы между временными точками и корректность операций сложения/вычитания.

Поддерживаемые единицы включают:

  • NANOS
  • MICROS
  • MILLIS
  • SECONDS
  • MINUTES
  • HOURS
  • HALF_DAYS
  • DAYS
  • WEEKS
  • MONTHS
  • YEARS
  • DECADES
  • CENTURIES
  • MILLENNIA
  • ERAS

Эти единицы делятся на две фундаментальные группы:

  • Точные (fixed-length units): наносекунды, микросекунды, миллисекунды, секунды, минуты, часы, половины суток
  • Календарные (variable-length units): дни и выше (недели, месяцы, годы и т.д.)

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


Точные единицы измерения

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

Наносекунды, микросекунды, миллисекунды

Эти единицы используются для низкоуровневых операций:

  • NANOS — базовая единица точности
  • MICROS — 1 000 наносекунд
  • MILLIS — 1 000 000 наносекунд

Они применяются в работе с Instant и Duration, где важна абсолютная точность.

Секунды, минуты, часы

Следующий уровень агрегирования:

  • SECONDS = 1 000 000 000 наносекунд
  • MINUTES = 60 секунд
  • HOURS = 60 минут

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

HALF_DAYS

Половина суток фиксируется как 12 часов. Эта единица используется редко, но важна при работе с 12-часовыми циклами и некоторыми календарными представлениями.


Календарные единицы

Календарные единицы вводят зависимость от структуры календаря, что делает их результат контекстно-зависимым.

Дни

День в js-joda не всегда равен 24 часам в абсолютном смысле. Его длительность зависит от:

  • переходов на летнее/зимнее время
  • временной зоны
  • календарной системы

В ZonedDateTime добавление одного дня может изменить абсолютную длительность интервала.

Недели

Неделя трактуется как фиксированное смещение в 7 календарных дней. Однако при работе с временными зонами итоговая длительность в часах может варьироваться.

Месяцы

Месяц является одной из наиболее вариативных единиц:

  • 28–31 день в григорианском календаре
  • зависит от конкретной даты
  • не имеет фиксированной длительности в секундах

Операции с месяцами выполняются только на уровнях LocalDate и выше.

Годы

Год также относится к календарным единицам:

  • 365 или 366 дней
  • зависит от високосности

Добавление одного года сохраняет календарную логику даты, но не гарантирует фиксированную длительность.


Эпохальные единицы

ChronoUnit включает крупномасштабные единицы, предназначенные для исторических и астрономических вычислений:

  • DECADES — 10 лет
  • CENTURIES — 100 лет
  • MILLENNIA — 1000 лет
  • ERAS — эпохи календарной системы

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


Duration и измерение абсолютного времени

Duration представляет собой измерение времени в фиксированных единицах, основанных на абсолютной шкале:

  • наносекунды
  • секунды
  • минуты
  • часы

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

Принцип работы Duration:

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

Пример логики:

  • 3600 секунд всегда равны одному часу
  • 86400 секунд равны одному дню только в идеализированном случае

Period и календарная арифметика

Period представляет календарные интервалы:

  • годы
  • месяцы
  • дни

В отличие от Duration, Period сохраняет структуру календаря, а не абсолютную длительность.

Особенности:

  • 1 месяц + 1 месяц ≠ фиксированное количество дней
  • результат зависит от исходной даты
  • используется с LocalDate и ZonedDateTime

Period корректно работает с неравномерными интервалами, сохраняя смысл календарных операций.


Совместимость ChronoUnit с временными типами

Разные типы js-joda поддерживают разные подмножества ChronoUnit.

Instant

Поддерживает только точные единицы:

  • NANOS
  • MICROS
  • MILLIS
  • SECONDS
  • MINUTES
  • HOURS
  • DAYS (в виде фиксированного преобразования)

Не поддерживает месяцы и годы.

LocalDate

Поддерживает календарные единицы:

  • DAYS
  • WEEKS
  • MONTHS
  • YEARS

Операции выполняются без учета времени суток.

LocalTime

Работает только с точными единицами:

  • NANOS
  • SECONDS
  • MINUTES
  • HOURS

ZonedDateTime

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


Операции преобразования единиц

js-joda предоставляет унифицированные операции:

plus / minus с ChronoUnit

Позволяет добавлять или вычитать единицы:

  • добавление часов
  • вычитание дней
  • смещение на недели

Поведение зависит от типа даты.

until

Используется для вычисления разницы между двумя моментами времени в заданной единице:

  • start.until(end, ChronoUnit.DAYS)
  • start.until(end, ChronoUnit.MONTHS)

Результат зависит от природы единицы: для точных — фиксированное число, для календарных — вычисление через календарную модель.

between

Аналогично until, но с измененным порядком аргументов в некоторых API-обертках. Возвращает количество единиц между двумя моментами.


Особенности переходов временных зон

В ZonedDateTime система единиц измерения времени сталкивается с эффектами переходов DST:

  • день может содержать 23 или 25 часов
  • добавление одного дня не гарантирует +24 часа в абсолютном времени
  • ChronoUnit.DAYS интерпретируется как календарный день, а не фиксированный интервал

Это приводит к различию между:

  • Duration.ofHours(24)
  • plus(1, ChronoUnit.DAYS)

Первое — фиксированный интервал, второе — календарное смещение.


Сравнение точных и календарных единиц

Ключевое различие систем выражается в двух моделях:

  • Физическая модель времени: Duration, NANOS–HOURS
  • Календарная модель времени: Period, DAYS–YEARS

Физическая модель:

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

Календарная модель:

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

Преобразование между моделями

Переход между Duration и Period невозможен напрямую без контекста даты:

  • Duration требует абсолютного начала отсчета
  • Period требует календарной точки отсчета

Для преобразования используется:

  • ZonedDateTime для связывания календаря и времени
  • LocalDateTime для локальных операций без зоны

Внутренние правила вычислений ChronoUnit

При работе с ChronoUnit библиотека применяет следующие принципы:

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

Значение системы единиц в архитектуре js-joda

Система ChronoUnit и связанные типы формируют единый слой абстракции, который:

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

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