Преобразование между Instant и другими типами

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

Ключевая особенность Instant — отсутствие контекста. Он не содержит информации о:

  • часовом поясе;
  • календарной системе;
  • локальном времени;
  • смещении (offset), если не преобразован явно.

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


Преобразование Instant из эпохи и обратно

Создание Instant из epoch-значений

Одним из основных способов получения Instant является работа с Unix-эпохой:

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

const i1 = Instant.ofEpochSecond(0)
const i2 = Instant.ofEpochMilli(0)
  • ofEpochSecond — интерпретация секунд с 1970-01-01T00:00:00Z
  • ofEpochMilli — интерпретация миллисекунд

Также возможен обратный переход:

const instant = Instant.now()

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

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


Преобразование Instant в ZonedDateTime

Наиболее частый сценарий — перевод Instant в локализованное представление через временную зону.

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

const instant = Instant.now()
const zone = ZoneId.of('Europe/Moscow')

const zoned = instant.atZone(zone)

Смысл преобразования

Instant + ZoneIdZonedDateTime

Результат включает:

  • календарную дату;
  • локальное время;
  • смещение UTC;
  • исходную временную зону.

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


Преобразование Instant в LocalDateTime

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

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

const instant = Instant.now()
const zone = ZoneId.of('Asia/Almaty')

const localDateTime = instant.atZone(zone).toLocalDateTime()

Характеристика результата

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

Преобразование Instant в LocalDate

Если требуется только календарная дата без времени:

const instant = Instant.now()
const zone = ZoneId.of('Asia/Almaty')

const localDate = instant.atZone(zone).toLocalDate()

Особенности

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

Преобразование Instant в LocalTime

Для извлечения только времени суток:

const instant = Instant.now()
const zone = ZoneId.of('Asia/Almaty')

const localTime = instant.atZone(zone).toLocalTime()

Логика преобразования

  • дата игнорируется;
  • учитывается смещение временной зоны;
  • результат представляет локальное время суток.

Преобразование Instant в OffsetDateTime

OffsetDateTime добавляет фиксированное смещение UTC без полноценной временной зоны.

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

const instant = Instant.now()

const offsetDateTime = instant.atOffset(ZoneOffset.UTC)

Отличие от ZonedDateTime

  • OffsetDateTime оперирует фиксированным offset;
  • не учитывает правила перехода на летнее/зимнее время;
  • ZonedDateTime включает полные правила зоны.

Обратные преобразования в Instant

Из ZonedDateTime

const instant = zonedDateTime.toInstant()

Из LocalDateTime

Так как LocalDateTime не содержит зоны, требуется явное указание:

const instant = localDateTime.atZone(zone).toInstant()

Из OffsetDateTime

const instant = offsetDateTime.toInstant()

Потери информации при преобразованиях

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

При переходе Instant → LocalDateTime

  • теряется временная зона;
  • сохраняется только «человеческое» время;
  • возможны разные интерпретации одного и того же Instant.

При переходе Instant → LocalDate

  • теряется время суток;
  • сохраняется только календарная дата;
  • результат зависит от зоны.

При переходе Instant → LocalTime

  • теряется дата;
  • сохраняется только момент суток.

Роль временной зоны в преобразованиях

Любое преобразование Instant в локальные типы невозможно без ZoneId.

Instant → ZoneId → LocalDateTime / LocalDate / LocalTime

Разные зоны дают разные результаты:

const instant = Instant.parse('2024-01-01T00:00:00Z')

const moscow = instant.atZone(ZoneId.of('Europe/Moscow'))
const tokyo = instant.atZone(ZoneId.of('Asia/Tokyo'))

Один и тот же Instant приводит к разным календарным датам и времени в разных регионах.


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

Парсинг

const instant = Instant.parse('2024-05-01T10:15:30Z')

Формат строго соответствует ISO-8601 и всегда предполагает UTC.

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

const str = instant.toString()

Результат всегда нормализован в UTC.


Усечение Instant до единиц времени

Instant поддерживает усечение через ChronoUnit, что часто используется перед конвертациями:

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

const truncated = instant.truncatedTo(ChronoUnit.SECONDS)

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

  • NANOS
  • MICROS
  • MILLIS
  • SECONDS

Усечение полезно при согласовании с системами, не поддерживающими высокую точность.


Типовые сценарии преобразований

Сценарий логирования

const instant = Instant.now()
const local = instant.atZone(ZoneId.of('Asia/Almaty')).toLocalDateTime()

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


Сценарий хранения времени в БД

const instant = Instant.now()
const millis = instant.toEpochMilli()

Сохраняется как числовое значение.


Сценарий отображения пользователю

const instant = Instant.now()

const view = instant
  .atZone(userZone)
  .toLocalDateTime()

Сценарий межсистемного обмена

const instant = Instant.parse(payload.timestamp)
const normalized = instant.toEpochMilli()

Особенности точности и округления

При преобразованиях следует учитывать:

  • Instant всегда оперирует наносекундами внутри модели js-joda;
  • toEpochMilli() выполняет округление вниз;
  • ChronoUnit влияет на потерю точности при усечении.

Взаимосвязь Instant и календарных типов

Структура преобразований в js-joda выстраивается вокруг одной логики:

  • Instant — абсолютная точка времени;
  • ZoneId — контекст интерпретации;
  • ZonedDateTime — полное представление;
  • LocalDateTime / LocalDate / LocalTime — частичные представления.

Каждое преобразование является либо добавлением контекста (zone), либо его удалением (local extraction), либо нормализацией (epoch conversion).


Ошибки при преобразованиях

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

// некорректно
const local = Instant.now().toLocalDateTime()

Instant не имеет такого метода, требуется зона.

Неправильная интерпретация epoch

Instant.ofEpochSecond(1000)

Может быть ошибочно воспринято как миллисекунды, хотя это секунды.

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

const data = {
  time: instant.toString()
}

Без зоны невозможно восстановить локальное представление.


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

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

Instant → ZoneId → целевой тип → (LocalDateTime | LocalDate | LocalTime | ZonedDateTime | OffsetDateTime)

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