Округление временных значений

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

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

Типичные сценарии:

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

Метод truncatedTo

Ключевой механизм округления в js-joda — метод truncatedTo(unit).

Он доступен у:

  • Instant
  • LocalTime
  • LocalDateTime
  • ZonedDateTime

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

Пример усечения до секунд

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

const now = Instant.now();

const truncated = now.truncatedTo(ChronoUnit.SECONDS);

Результат:

  • наносекунды удаляются
  • остаются только секунды

Усечение LocalDateTime

import { LocalDateTime, ChronoUnit } from '@js-joda/core';

const dt = LocalDateTime.parse('2026-05-25T14:37:52.987');

const result = dt.truncatedTo(ChronoUnit.MINUTES);

Результат:

2026-05-25T14:37

Все значения после минут (секунды и наносекунды) становятся нулевыми.


Поведение для разных единиц времени

Операция усечения работает иерархически:

  • DAYS → обнуляет время полностью
  • HOURS → обнуляет минуты, секунды, наносекунды
  • MINUTES → обнуляет секунды и наносекунды
  • SECONDS → обнуляет наносекунды

Пример:

dt.truncatedTo(ChronoUnit.HOURS);
2026-05-25T14:00

Округление вниз (floor rounding)

По сути truncatedTo — это всегда округление вниз.

Пример:

LocalTime.parse('10:29:59').truncatedTo(ChronoUnit.HOURS);

Результат:

10:00

Никаких правил «0.5 и выше» не применяется. Поведение строго детерминировано: всё, что меньше единицы — отбрасывается.


Округление вверх (ceil rounding)

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

Округление вверх до минут

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

const time = LocalTime.parse('10:29:10');

const ceil = time
  .plusMinutes(1)
  .truncatedTo(ChronoUnit.MINUTES);

Логика:

  1. добавляется 1 минута
  2. затем выполняется усечение

Результат:

10:30

Особенность: такой подход может приводить к переходу через границы (например, 23:59 → 00:00 следующего дня при работе с LocalTime через LocalDateTime или ZonedDateTime).


Округление до ближайшего значения

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

Пример: округление до ближайшей минуты

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

const time = LocalTime.parse('10:29:40');

const seconds = time.toSecondOfDay();

const rounded = (seconds % 60 >= 30)
  ? time.plusMinutes(1).truncatedTo(ChronoUnit.MINUTES)
  : time.truncatedTo(ChronoUnit.MINUTES);

Результаты:

  • 10:29:2010:29
  • 10:29:4010:30

Instant и работа с эпохой

Instant представляет момент времени в UTC и особенно часто используется для округления временных меток в системах логирования и событий.

Округление Instant

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

const instant = Instant.parse('2026-05-25T14:37:52.987Z');

const truncated = instant.truncatedTo(ChronoUnit.MINUTES);

Результат:

2026-05-25T14:37:00Z

Особенность Instant

Все операции выполняются в UTC, независимо от локальной зоны.


ZonedDateTime и влияние временной зоны

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

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

const zdt = ZonedDateTime
  .parse('2026-05-25T14:37:52+05:00[Asia/Almaty]');

const result = zdt.truncatedTo(ChronoUnit.HOURS);

Результат:

2026-05-25T14:00+05:00[Asia/Almaty]

Важно:

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

Наносекунды и точность

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

Пример обнуления наносекунд

const t = LocalTime.parse('12:15:30.123456789');

const truncated = t.truncatedTo(ChronoUnit.SECONDS);

Результат:

12:15:30

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


Комбинирование округления с арифметикой времени

Часто округление используется вместе с операциями plus, minus.

Пример нормализации интервала

const normalized = dt
  .minusMinutes(7)
  .truncatedTo(ChronoUnit.HOURS);

Это позволяет «сдвинуть окно» и затем выровнять данные по часам.


Типичные ошибки при округлении

1. Ожидание математического округления

truncatedTo не округляет, а отсекает. Ожидание поведения типа 10:59 → 11:00 приводит к логическим ошибкам.


2. Игнорирование временной зоны

При переходе между LocalDateTime и ZonedDateTime округление может давать разные результаты из-за смещения зоны.


3. Потеря данных при частом усечении

Последовательное усечение:

dt.truncatedTo(ChronoUnit.SECONDS)
  .truncatedTo(ChronoUnit.MINUTES);

не эквивалентно одному усечению до минут только в логике анализа, но может влиять на читаемость и намерение кода.


4. Использование Instant без понимания UTC

Округление Instant всегда происходит в UTC, что может не совпадать с локальной логикой приложения.


Практика использования округления в системах

Округление временных значений применяется в архитектурных сценариях:

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

Пример ключа для кэша:

const key = dt.truncatedTo(ChronoUnit.MINUTES).toString();

Сравнение стратегий округления

Метод Поведение Применение
truncatedTo Округление вниз логирование, группировка
plus + truncatedTo Округление вверх интервальные расчёты
условное сравнение округление до ближайшего аналитика, метрики

Работа с длительностями и округлением

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

import { Duration, ChronoUnit } from '@js-joda/core';

const d = Duration.ofSeconds(125);

const normalized = d.truncatedTo(ChronoUnit.MINUTES);

Результат:

PT2M

Остаётся только целая часть минут, секунды отбрасываются.


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

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

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

Слишком грубое округление приводит к потере детализации, слишком точное — к росту объёма данных.


Стабильность и предсказуемость операций

Округление в js-joda обладает строгой детерминированностью:

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

Это делает truncatedTo удобным для распределённых систем, где временные значения должны совпадать между узлами.