Работа с timestamp

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

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

Создание текущего timestamp:

import { Instant } from 'js-joda';

const now = Instant.now();

Instant.now() использует системные часы и возвращает текущее значение в UTC.

Создание через epoch milliseconds:

const instant = Instant.ofEpochMilli(1710000000000);

Создание через секунды эпохи:

const instantSec = Instant.ofEpochSecond(1710000000);

Дополнительно поддерживается указание наносекундной части:

const precise = Instant.ofEpochSecond(1710000000, 500000000);

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

Epoch time и представления timestamp

Timestamp в js-joda можно представлять в двух основных формах:

  • секунды с начала эпохи (epochSecond)
  • миллисекунды с начала эпохи (toEpochMilli)

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

const instant = Instant.now();

const millis = instant.toEpochMilli();
const seconds = instant.epochSecond();

Разница между ними заключается в точности: миллисекунды используются в JavaScript-экосистеме как стандарт, тогда как секунды удобны для хранения и передачи в некоторых API и базах данных.

Перевод из Instant обратно в epoch:

const fromMillis = Instant.ofEpochMilli(millis);
const fromSeconds = Instant.ofEpochSecond(seconds);

Преобразование между Instant и Date

В экосистеме JavaScript часто требуется взаимодействие с Date, однако js-joda избегает его использования в логике. Конвертация выполняется явно:

const instant = Instant.now();

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

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

Работа с ISO-строками timestamp

Instant поддерживает парсинг и форматирование в стандарте ISO-8601.

Парсинг строки:

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

Форматирование:

const str = instant.toString();

Результат всегда нормализуется к UTC и заканчивается символом Z, обозначающим нулевой сдвиг часового пояса.

Сравнение timestamp

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

const a = Instant.parse('2025-05-25T10:00:00Z');
const b = Instant.parse('2025-05-25T12:00:00Z');

const isBefore = a.isBefore(b);
const isAfter = b.isAfter(a);
const isEqual = a.equals(b);

Дополнительно доступен метод compareTo:

const result = a.compareTo(b);

Возвращаемые значения:

  • отрицательное число — меньше
  • 0 — равны
  • положительное — больше

Операции смещения timestamp

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

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

const now = Instant.now();

const later = now.plus(Duration.ofSeconds(30));
const earlier = now.minus(Duration.ofMinutes(5));

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

Ограничения Instant и отсутствие часового пояса

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

Пример преобразования:

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

const instant = Instant.now();

const zoned = instant.atZone(ZoneId.of('Europe/Paris'));

Таким образом timestamp остаётся неизменным, а интерпретация зависит от зоны.

Обратное преобразование:

const backToInstant = zoned.toInstant();

ZonedDateTime и timestamp в реальных сценариях

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

const zoned = ZonedDateTime.now(ZoneId.of('Asia/Almaty'));
const instant = zoned.toInstant();
const millis = instant.toEpochMilli();

Такая модель позволяет хранить данные в UTC, а отображать в локальном формате.

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

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

const instant = Instant.ofEpochSecond(0, 123456789);

При преобразовании в Date точность теряется:

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

Таким образом, Date всегда работает в миллисекундной гранулярности.

Нормализация timestamp

Любой Instant автоматически нормализуется:

  • секунды приводятся к диапазону
  • наносекунды корректируются при переполнении
const instant = Instant.ofEpochSecond(1, 1_500_000_000);

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

Использование timestamp в логировании

Timestamp часто используется для фиксации событий:

const eventTime = Instant.now();

const logEntry = {
  type: 'USER_LOGIN',
  timestamp: eventTime.toEpochMilli()
};

Альтернативно, при необходимости высокой точности:

const logEntry = {
  type: 'USER_LOGIN',
  timestamp: eventTime.toString()
};

ISO-строка обеспечивает переносимость между системами.

Сравнение Instant с Date

Различия между Instant и Date можно свести к нескольким аспектам:

  • Instant не зависит от локальной зоны
  • Date всегда связан с локальной интерпретацией при форматировании
  • Instant поддерживает высокоуровневую арифметику через js-joda API
  • Date ограничен устаревшими методами и не имеет строгой модели времени

Преобразование:

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

const restored = Instant.ofEpochMilli(date.getTime());

Обработка timestamp в диапазонах

Типичный сценарий — проверка попадания времени в интервал:

const start = Instant.parse('2025-01-01T00:00:00Z');
const end = Instant.parse('2025-12-31T23:59:59Z');

const current = Instant.now();

const inRange = !current.isBefore(start) && !current.isAfter(end);

Такая логика остаётся корректной независимо от локальных настроек системы.

Преобразование timestamp для API

При работе с внешними сервисами timestamp часто передаётся в одном из форматов:

  • epoch milliseconds
  • ISO-8601 string

Примеры:

const instant = Instant.now();

const payloadA = {
  timestamp: instant.toEpochMilli()
};

const payloadB = {
  timestamp: instant.toString()
};

Выбор формата зависит от требований API, при этом внутреннее представление остаётся неизменным.

Работа с отрицательными timestamp

js-joda поддерживает значения до эпохи Unix:

const beforeEpoch = Instant.ofEpochSecond(-1000);

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

Стабильность timestamp при сериализации

При сериализации в JSON Instant требует явного преобразования:

const instant = Instant.now();

const json = JSON.stringify({
  time: instant.toEpochMilli()
});

Обратное восстановление:

const parsed = JSON.parse(json);
const restored = Instant.ofEpochMilli(parsed.time);

Использование ISO-строк:

const jsonIso = JSON.stringify({
  time: instant.toString()
});

const restoredIso = Instant.parse(JSON.parse(jsonIso).time);

Использование timestamp в распределённых системах

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

const event = {
  id: 'evt_1',
  createdAt: Instant.now().toString()
};

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