Библиотека js-joda реализует модель времени, основанную на API
java.time. Одной из ключевых особенностей является
поддержка времени с точностью до наносекунд. В отличие от стандартного
объекта Date в JavaScript, ограниченного миллисекундами,
Js-joda предоставляет полноценную работу с высокоточной временной
шкалой.
DateОбъект Date хранит время как количество миллисекунд с
эпохи Unix:
const now = new Date()
console.log(now.getMilliseconds())
Проблемы такого подхода:
Для систем мониторинга, распределённых вычислений, трейдинга, телеметрии и научных расчётов миллисекунд недостаточно.
Наносекунда (nanosecond) — одна миллиардная доля
секунды.
Соотношения единиц времени:
| Единица | Значение |
|---|---|
| 1 секунда | 1 000 миллисекунд |
| 1 миллисекунда | 1 000 микросекунд |
| 1 микросекунда | 1 000 наносекунд |
| 1 секунда | 1 000 000 000 наносекунд |
Js-joda хранит наносекунды отдельно от секундной части времени, благодаря чему достигается высокая точность без потерь.
InstantInstant представляет момент времени на глобальной
временной шкале UTC.
const { Instant } = require('@js-joda/core')
const instant = Instant.now()
console.log(instant.toString())
Пример вывода:
2026-05-24T12:45:18.123456789Z
Последние 9 цифр после точки — наносекунды.
Метод nano() возвращает наносекундную часть времени.
const { LocalTime } = require('@js-joda/core')
const time = LocalTime.parse('12:30:15.123456789')
console.log(time.nano())
Результат:
123456789
Важно понимать:
nano() возвращает часть секунды;0 — 999999999
LocalTimeconst { LocalTime } = require('@js-joda/core')
const time = LocalTime.of(
10,
15,
30,
987654321
)
console.log(time.toString())
Результат:
10:15:30.987654321
Аргументы метода:
| Параметр | Значение |
|---|---|
| hour | часы |
| minute | минуты |
| second | секунды |
| nanoOfSecond | наносекунды |
LocalDateTimeconst { LocalDateTime } = require('@js-joda/core')
const dateTime = LocalDateTime.of(
2026,
5,
24,
14,
22,
10,
111222333
)
console.log(dateTime.toString())
Instant.ofEpochSecondМетод позволяет задавать:
const { Instant } = require('@js-joda/core')
const instant = Instant.ofEpochSecond(
1700000000,
555666777
)
console.log(instant.toString())
Если количество наносекунд превышает предел одной секунды, Js-joda автоматически нормализует значение.
const { Instant } = require('@js-joda/core')
const instant = Instant.ofEpochSecond(
10,
1_500_000_000
)
console.log(instant.toString())
Результат:
1970-01-01T00:00:11.500Z
Что произошло:
| Исходно | После нормализации |
|---|---|
| 10 секунд | 11 секунд |
| 1 500 000 000 нс | 500 000 000 нс |
plusNanosconst { LocalTime } = require('@js-joda/core')
const time = LocalTime.parse(
'23:59:59.999999999'
)
const next = time.plusNanos(1)
console.log(next.toString())
Результат:
00:00
Произошёл переход через границу суток.
minusNanosconst { LocalTime } = require('@js-joda/core')
const time = LocalTime.parse(
'00:00:00.000000001'
)
const prev = time.minusNanos(1)
console.log(prev.toString())
Результат:
23:59:59.999999999
DurationDuration хранит промежуток времени с наносекундной
точностью.
const { Duration } = require('@js-joda/core')
const duration = Duration.ofNanos(500)
console.log(duration.toString())
Результат:
PT0.0000005S
const { Duration } = require('@js-joda/core')
const a = Duration.ofNanos(400)
const b = Duration.ofNanos(700)
const result = a.plus(b)
console.log(result.toNanos())
Результат:
1100
toNanosconst { Duration } = require('@js-joda/core')
const duration = Duration.ofSeconds(2)
console.log(duration.toNanos())
Результат:
2000000000
const {
Instant,
Duration
} = require('@js-joda/core')
const start = Instant.parse(
'2026-05-24T10:00:00.000000100Z'
)
const end = Instant.parse(
'2026-05-24T10:00:00.000000900Z'
)
const diff = Duration.between(start, end)
console.log(diff.toNanos())
Результат:
800
Js-joda сохраняет точность при преобразовании в строку.
const { LocalTime } = require('@js-joda/core')
const time = LocalTime.of(
12,
0,
0,
123456789
)
console.log(time.toString())
Результат:
12:00:00.123456789
Метод truncatedTo() позволяет отбросить лишнюю
точность.
const {
LocalTime,
ChronoUnit
} = require('@js-joda/core')
const time = LocalTime.parse(
'10:15:30.987654321'
)
const truncated = time.truncatedTo(
ChronoUnit.MILLIS
)
console.log(truncated.toString())
Результат:
10:15:30.987
ChronoUnitДля наносекунд используется:
ChronoUnit.NANOS
Пример:
const {
LocalDateTime,
ChronoUnit
} = require('@js-joda/core')
const dateTime = LocalDateTime.now()
const updated = dateTime.plus(
500,
ChronoUnit.NANOS
)
console.log(updated.toString())
const { Instant } = require('@js-joda/core')
const a = Instant.parse(
'2026-05-24T10:00:00.000000001Z'
)
const b = Instant.parse(
'2026-05-24T10:00:00.000000002Z'
)
console.log(a.isBefore(b))
Результат:
true
Сравнение происходит с учётом наносекунд.
DateПри конвертации в стандартный JavaScript Date
наносекунды теряются.
const { Instant } = require('@js-joda/core')
const instant = Instant.parse(
'2026-05-24T10:00:00.123456789Z'
)
const millis = instant.toEpochMilli()
console.log(millis)
Результат содержит только миллисекунды:
123
Часть:
456789
будет потеряна.
JSON.stringify({
time: new Date()
})
Точность ограничена миллисекундами.
const { Instant } = require('@js-joda/core')
const payload = {
time: Instant.now().toString()
}
console.log(JSON.stringify(payload))
Результат:
{
"time":"2026-05-24T12:10:15.123456789Z"
}
const { Instant } = require('@js-joda/core')
function log(message) {
const timestamp = Instant.now()
console.log(
`[${timestamp}] ${message}`
)
}
log('Connection opened')
Пример:
[2026-05-24T12:10:15.123456789Z] Connection opened
const {
Instant,
Duration
} = require('@js-joda/core')
const start = Instant.now()
for (let i = 0; i < 1_000_000; i++) {}
const end = Instant.now()
const duration = Duration.between(
start,
end
)
console.log(duration.toNanos())
Многие современные СУБД поддерживают наносекундную точность:
| СУБД | Поддержка |
|---|---|
| PostgreSQL | микросекунды |
| Oracle | наносекунды |
| SQL Server | 100 нс |
| MongoDB | миллисекунды |
При использовании Js-joda важно учитывать ограничения конкретного драйвера и типа поля.
JavaScript использует тип Number на основе IEEE 754.
Максимальное безопасное целое:
Number.MAX_SAFE_INTEGER
Результат:
9007199254740991
При работе с огромными временными интервалами в наносекундах возможна потеря точности.
BigIntДля сверхбольших интервалов применяется BigInt.
const nanos = 1234567890123456789n
console.log(nanos)
Js-joda внутри старается избегать проблем переполнения, но при интеграции с пользовательским кодом это необходимо учитывать.
.plusNanos(1000)
Это:
1 микросекунда
а не 1 миллисекунда.
LocalTime.parse(
'10:00:00.123'
)
Это миллисекунды:
123000000 наносекунд
Datenew Date(
instant.toEpochMilli()
)
Наносекунды исчезают.
const {
Instant
} = require('@js-joda/core')
const events = []
function addEvent(name) {
events.push({
name,
createdAt: Instant.now()
})
}
addEvent('task-1')
addEvent('task-2')
console.log(events)
Даже события, созданные почти одновременно, будут иметь разные наносекундные значения.
events.sort((a, b) =>
a.createdAt.compareTo(
b.createdAt
)
)
Сортировка выполняется с учётом наносекундной точности.
const { Instant } = require('@js-joda/core')
function createId() {
return Instant.now()
.toEpochMilli()
.toString()
}
Для действительно уникальных идентификаторов миллисекунд недостаточно. Более надёжный вариант:
function createPreciseId() {
return Instant.now().toString()
}
Операции Js-joda являются неизменяемыми (immutable).
Каждое изменение создаёт новый объект:
const updated = instant.plusNanos(1)
Преимущества:
Недостаток:
| Класс | Поддержка наносекунд |
|---|---|
Instant |
Да |
LocalTime |
Да |
LocalDateTime |
Да |
OffsetDateTime |
Да |
ZonedDateTime |
Да |
Duration |
Да |
Period |
Нет |
Duration от
PeriodDurationХранит точное количество времени:
Duration.ofNanos(1)
PeriodХранит календарные единицы:
Period.ofDays(1)
Period не работает с наносекундами.
Наиболее надёжный формат хранения:
2026-05-24T12:10:15.123456789Z
Особенности:
Использовать:
Instant
Использовать:
LocalTime
LocalDateTime
Использовать:
Duration
DateКонвертацию выполнять только на границе интеграции со сторонними API.
Передавать время в ISO-8601 строках:
instant.toString()
Учитывать: