Truncation операции

В библиотеке js-joda усечение (truncation) представляет собой операцию приведения временного значения к более грубой точности путём обнуления всех полей меньшего порядка, чем выбранная единица измерения. Модель остаётся неизменяемой: каждое усечение возвращает новый экземпляр, не модифицируя исходный объект.

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


Механизм truncatedTo и его семантика

Основной метод усечения в js-joda — truncatedTo(unit), где unit задаётся через ChronoUnit.

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

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

const truncated = dt.truncatedTo(ChronoUnit.HOURS);
// 2026-05-25T14:00

Операция выполняется по следующему принципу:

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

Поддерживаемые единицы времени

Усечение опирается на ChronoUnit, который определяет гранулярность временной шкалы.

Наиболее часто используемые единицы:

  • DAYS
  • HOURS
  • MINUTES
  • SECONDS
  • MILLIS
  • NANOS

Пример последовательного уменьшения точности:

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

base.truncatedTo(ChronoUnit.MINUTES);
// 2026-05-25T14:37

base.truncatedTo(ChronoUnit.SECONDS);
// 2026-05-25T14:37:52

base.truncatedTo(ChronoUnit.MILLIS);
// 2026-05-25T14:37:52.123

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

LocalDateTime

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

LocalDateTime.parse('2026-05-25T14:37:52')
  .truncatedTo(ChronoUnit.DAYS);
// 2026-05-25T00:00

Instant

Instant представляет момент времени в UTC-эпохе, и усечение применяется к абсолютному времени.

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

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

instant.truncatedTo(ChronoUnit.SECONDS);
// 2026-05-25T14:37:52Z

ZonedDateTime

Для временных зон усечение производится в контексте конкретного смещения.

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

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

zdt.truncatedTo(ChronoUnit.HOURS);
// 2026-05-25T14:00+05:00[Asia/Almaty]

Внутренняя логика обнуления полей

Усечение не выполняет округление и не учитывает «ближайшее значение». Оно действует детерминированно:

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

Пример:

LocalDateTime.parse('2026-05-25T00:00:00.000').truncatedTo(ChronoUnit.HOURS);
// остаётся 2026-05-25T00:00

Особенности работы с наносекундами

Точность до наносекунд поддерживается, но реальная полезность зависит от платформы исполнения JavaScript.

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

dt.truncatedTo(ChronoUnit.NANOS);
// значение не изменяется

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


Ограничения и неподдерживаемые операции

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

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

  • корректно: часы, минуты, секунды
  • некорректно: месяцы, годы, недели (в контексте truncation)

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


Иммутабельность результата

Все временные типы js-joda неизменяемы. Операция усечения возвращает новый объект:

const original = LocalDateTime.parse('2026-05-25T14:37:52.123');
const truncated = original.truncatedTo(ChronoUnit.MINUTES);

original.toString();  // 2026-05-25T14:37:52.123
truncated.toString(); // 2026-05-25T14:37

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


Усечение и временные зоны

При работе с ZonedDateTime усечение выполняется с учётом локального представления времени, а затем пересчитывается в абсолютный момент.

Особое внимание требуется к зонам с переходами:

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

Усечение не устраняет эти эффекты, а лишь изменяет локальное представление времени.


Практические сценарии применения

Нормализация временных меток

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

const normalized = instant.truncatedTo(ChronoUnit.SECONDS);

Группировка событий

При агрегации логов или событий временные метки приводятся к общей сетке:

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

Кэширование и дедупликация

Усечение позволяет формировать ключи без избыточной точности:

const cacheKey = `events:${instant.truncatedTo(ChronoUnit.HOURS)}`;

Аналитика временных рядов

При построении временных рядов данные часто агрегируются по фиксированным интервалам:

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

Сравнение с аналогичной концепцией в java.time

Механизм js-joda повторяет поведение Java java.time:

  • идентичный метод truncatedTo
  • аналогичная семантика обнуления полей
  • те же ограничения по ChronoUnit

Это обеспечивает переносимость логики между JVM и JavaScript-окружениями без изменения алгоритмов работы с датами.


Типовые ошибки при использовании

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

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

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

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

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