Использование Instant для timestamp

В библиотеке js-joda тип Instant служит для представления конкретного момента времени на временной шкале UTC без привязки к часовому поясу и календарным системам. Это базовый строительный блок для работы с временными метками, аналогичный по смыслу Unix epoch time, но с более строгой моделью и расширенными возможностями точности.

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


Создание Instant

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

Текущий момент времени

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

const now = Instant.now();

Метод Instant.now() возвращает текущее время системы в UTC. Это основной способ получения временной метки для логирования, аудита и фиксации событий.


Создание из секунд эпохи

const instant = Instant.ofEpochSecond(1700000000);

Метод ofEpochSecond принимает количество секунд, прошедших с Unix epoch. Это удобный способ работы с внешними API, которые возвращают время в секундах.

Также допускается указание наносекундной части:

const instant = Instant.ofEpochSecond(1700000000, 500000000);

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


Создание из миллисекунд

const instant = Instant.ofEpochMilli(Date.now());

Метод ofEpochMilli используется для совместимости с JavaScript Date, где время выражается в миллисекундах. Это наиболее распространённый мост между стандартным API JavaScript и js-joda.


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

Instant поддерживает ISO-8601 формат:

const instant = Instant.parse('2025-05-01T12:30:45Z');

Строка должна содержать временную зону Z (UTC), так как Instant не допускает локальных смещений. Попытка передать строку с часовым поясом типа +03:00 требует предварительной нормализации.


Внутреннее устройство Instant

Instant хранит время как комбинацию двух значений:

  • секунды с эпохи Unix
  • наносекунды внутри секунды

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

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

epochSeconds: number
nanoAdjustment: number (0–999,999,999)

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


Получение значений из Instant

Секунды эпохи

const seconds = instant.epochSecond();

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


Миллисекунды

const millis = instant.toEpochMilli();

Это наиболее совместимый формат для взаимодействия с JavaScript экосистемой.


Наносекунды

const nano = instant.nano();

Возвращает наносекундную часть внутри текущей секунды.


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

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

Добавление времени

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

const later = instant.plus(Duration.ofMinutes(10));

Объект Duration строго типизирует временные интервалы, исключая неоднозначности.


Вычитание времени

const earlier = instant.minus(Duration.ofSeconds(30));

Операции возвращают новый объект, так как Instant является неизменяемым.


Разница между моментами времени

Для вычисления интервала используется Duration.between:

const start = Instant.now();
const end = Instant.now();

const diff = Duration.between(start, end);

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


Сравнение Instant

Instant поддерживает естественные операции сравнения:

instant1.isBefore(instant2);
instant1.isAfter(instant2);

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

Также доступен метод:

instant1.equals(instant2);

Он проверяет полное совпадение временной метки.


Конвертация между системами времени

Конвертация из JavaScript Date

const instant = Instant.ofEpochMilli(new Date().getTime());

Конвертация обратно в Date

const date = new Date(instant.toEpochMilli());

Несмотря на различие моделей, этот мост остаётся основным способом взаимодействия js-joda с существующим кодом.


Работа с UTC и часовыми поясами

Instant всегда находится в UTC и не содержит информации о зоне. Для отображения локального времени используется связка с ZonedDateTime:

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

const zdt = instant.atZone(ZoneId.of('Europe/Moscow'));

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


Форматирование и сериализация

Instant обычно сериализуется в ISO-8601:

instant.toString();

Результат:

2025-05-01T12:30:45Z

Этот формат широко используется в API и логировании.


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

Instant является стандартным выбором для отметки событий:

const logEntry = {
  message: 'User login',
  timestamp: Instant.now().toString()
};

Такой подход обеспечивает:

  • независимость от локального времени
  • корректную сортировку событий
  • совместимость между системами

Использование в базах данных

При хранении временных меток Instant часто преобразуется в:

  • bigint (epoch milliseconds)
  • timestamp with time zone (в SQL)
  • ISO-строку

Пример подготовки данных:

const record = {
  createdAt: instant.toEpochMilli()
};

Ограничения Instant

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

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

Для таких задач используется LocalDateTime или ZonedDateTime.


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

Игнорирование UTC

Использование Instant без понимания его UTC-природы приводит к ошибкам отображения времени в интерфейсах.

Смешивание с Date без конверсии

// некорректная логика сравнения
if (instant > new Date()) {}

Правильный вариант:

if (instant.toEpochMilli() > Date.now()) {}

Попытка работать с календарём

instant.getYear(); // отсутствует

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


Практические сценарии использования

Очереди событий

Instant используется как временная метка событий в message brokers и event sourcing:

const event = {
  type: 'ORDER_CREATED',
  time: Instant.now()
};

Кэширование

Для контроля TTL:

const expiresAt = Instant.now().plus(Duration.ofMinutes(5));

Сортировка данных

events.sort((a, b) =>
  a.timestamp.compareTo(b.timestamp)
);

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

Instant обеспечивает точность до наносекунд, однако реальная точность зависит от среды выполнения JavaScript. В большинстве браузеров и Node.js фактическая точность ограничена миллисекундами, но модель остаётся расширенной для совместимости с JVM-экосистемой, где js-joda изначально концептуально вдохновлён.


Иммутабельность и потокобезопасность

Все операции с Instant возвращают новый экземпляр. Это исключает:

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

Такая модель особенно важна в асинхронных системах и распределённых приложениях.