Арифметика с Instant

Instant в js-joda представляет собой момент времени в UTC, измеряемый относительно эпохи Unix (1970-01-01T00:00:00Z). Это неизменяемый тип, предназначенный для точной работы с временными метками, где отсутствует привязка к часовым поясам и календарным компонентам.

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

Instant хранит значение в виде:

  • секунд с начала эпохи
  • наносекундной доли текущей секунды

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

import { Instant } from 'js-joda';

const now = Instant.now();
const epochSeconds = now.epochSecond();
const nanoAdjustment = now.nano();

console.log(epochSeconds);
console.log(nanoAdjustment);

Любая арифметика с Instant всегда возвращает новый экземпляр, сохраняя неизменяемость исходного объекта.

Добавление и вычитание фиксированных единиц времени

Основной способ выполнения арифметики — методы plus и minus с указанием единиц времени через ChronoUnit.

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

const base = Instant.parse('2025-01-01T00:00:00Z');

const shiftedForward = base.plus(10, ChronoUnit.SECONDS);
const shiftedBack = base.minus(500, ChronoUnit.MILLIS);

console.log(shiftedForward.toString());
console.log(shiftedBack.toString());

Используемые единицы:

  • ChronoUnit.SECONDS
  • ChronoUnit.MILLIS
  • ChronoUnit.MICROS
  • ChronoUnit.NANOS

Механизм строго типизирован: попытка использовать календарные единицы (например, DAYS, MONTHS) для Instant допустима только в ограниченных случаях, и не всегда имеет смысл с точки зрения временной шкалы без часового пояса.

Арифметика через Duration

Более выразительный способ работы с временными интервалами — использование Duration. Этот подход предпочтителен при сложных вычислениях, связанных с временными интервалами.

import { Instant, Duration } from 'js-joda';

const start = Instant.parse('2025-01-01T00:00:00Z');

const duration = Duration.ofMinutes(90);
const end = start.plus(duration);

console.log(end.toString());

Аналогично выполняется вычитание:

const earlier = start.minus(Duration.ofHours(2));

Duration поддерживает:

  • секунды
  • миллисекунды
  • наносекунды
  • комбинированные интервалы

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

Ограничения календарной арифметики

Instant не предназначен для работы с календарными сущностями. Следующая операция концептуально некорректна:

import { Period } from 'js-joda';

const instant = Instant.now();
// некорректно по смыслу
const result = instant.plus(Period.ofDays(1));

Причина заключается в том, что Period оперирует календарными датами (дни, месяцы, годы), которые зависят от календарной системы и часового пояса. Instant же находится вне календарного контекста.

Для подобных операций требуется преобразование в ZonedDateTime или LocalDateTime.

Сравнение и относительная арифметика

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

import { Instant } from 'js-joda';

const t1 = Instant.parse('2025-01-01T00:00:00Z');
const t2 = t1.plusSeconds(30);

console.log(t2.isAfter(t1));
console.log(t1.isBefore(t2));
console.log(t1.compareTo(t2));

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

import { ChronoUnit } from 'js-joda';

const diff = t1.until(t2, ChronoUnit.SECONDS);
console.log(diff);

Результат будет отрицательным или положительным в зависимости от порядка аргументов.

Инкременты через специализированные методы

Для частых операций предусмотрены удобные методы:

  • plusSeconds
  • plusMillis
  • plusNanos
  • minusSeconds
  • minusMillis
  • minusNanos
const base = Instant.parse('2025-01-01T00:00:00Z');

const a = base.plusSeconds(10);
const b = base.plusMillis(250);
const c = base.minusNanos(1_000);

Эти методы являются обертками над более универсальным plus(long, unit) и minus(long, unit), но обеспечивают лучшую читаемость и сниженный риск ошибок в выборе единиц.

Работа с переполнением и точностью

Арифметика Instant выполняется с учетом ограничений диапазона времени. При выходе за допустимые границы (слишком далеко в прошлое или будущее) возникает исключение.

Наносекундная точность может приводить к неочевидным эффектам при сложении:

const t = Instant.parse('2025-01-01T00:00:00Z');
const result = t.plusMillis(1).plusNanos(500);

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

Комбинированные вычисления

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

import { Instant, Duration, ChronoUnit } from 'js-joda';

const base = Instant.now();

const result = base
  .plus(Duration.ofMinutes(5))
  .minus(120, ChronoUnit.SECONDS)
  .plusMillis(250);

Каждый шаг возвращает новый объект, что делает такие цепочки безопасными в многопоточном и асинхронном окружении.

Сдвиги во времени и практическая модель расчётов

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

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

Арифметика строится вокруг добавления фиксированных интервалов:

const createdAt = Instant.now();
const expiresAt = createdAt.plus(Duration.ofHours(24));

const isExpired = Instant.now().isAfter(expiresAt);

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

Преобразование результата арифметики

Результаты операций над Instant часто преобразуются в другие типы js-joda:

import { ZoneId } from 'js-joda';

const zoned = result.atZone(ZoneId.of('Europe/Berlin'));
console.log(zoned.toString());

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

Поведение при пограничных значениях

При работе с очень большими интервалами важно учитывать:

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

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

Модель неизменяемости в арифметике

Каждая операция над Instant следует функциональному подходу:

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

Это делает арифметику Instant устойчивой к побочным эффектам:

const a = Instant.now();
const b = a.plusSeconds(10);

console.log(a === b); // false