Точность и ограничения

Стандартный объект Date в JavaScript хранит время в миллисекундах. Это фундаментальное ограничение платформы, влияющее на любые операции с датой и временем. Библиотека js-joda наследует часть этих ограничений при взаимодействии с системным временем, однако внутри собственной модели предоставляет существенно более строгую и предсказуемую работу.

Основная проблема Date заключается в том, что:

  • время хранится как число миллисекунд от Unix Epoch;
  • отсутствует поддержка наносекунд;
  • вычисления зависят от часового пояса окружения;
  • API допускает невалидные преобразования;
  • многие операции мутируют объект.

js-joda устраняет большинство этих проблем за счёт:

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

Наносекундная точность

Одной из ключевых особенностей js-joda является поддержка наносекунд (nanoseconds).

В отличие от стандартного Date, библиотека позволяет хранить:

  • часы;
  • минуты;
  • секунды;
  • миллисекунды;
  • микросекунды;
  • наносекунды.

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

const { LocalTime } = require('@js-joda/core');

const time = LocalTime.of(12, 30, 15, 123456789);

console.log(time.toString());
// 12:30:15.123456789

Последний аргумент — количество наносекунд.


Внутренние ограничения точности

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

  • точностью хранения;
  • точностью системных часов.

Хранение

js-joda способен хранить значения до наносекунды:

const time = LocalTime.parse('10:15:30.999999999');

Получение текущего времени

При использовании:

Instant.now()

точность зависит от платформы JavaScript.

В большинстве сред:

  • браузеры предоставляют миллисекунды;
  • Node.js обычно предоставляет микросекунды или наносекунды через внутренние механизмы;
  • реальная точность ОС может быть ниже заявленной.

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


Диапазоны допустимых значений

Каждый временной тип в js-joda имеет строгие границы.

LocalDate

LocalDate.MIN
LocalDate.MAX

Поддерживаемый диапазон:

-999999999-01-01
до
+999999999-12-31

Это значительно больше диапазона стандартного Date.


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

Время суток ограничено:

00:00:00.000000000
—
23:59:59.999999999

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

Пример ошибки

LocalTime.of(25, 0);

Результат:

DateTimeException

Проверка диапазонов

Библиотека строго валидирует значения.

Неверный месяц

LocalDate.of(2025, 13, 1);

Неверный день

LocalDate.of(2025, 2, 30);

Неверная наносекунда

LocalTime.of(10, 0, 0, 1000000000);

Во всех случаях будет выброшено исключение.


Ограничения арифметики времени

Переполнение диапазона

При выходе за допустимый диапазон библиотека генерирует ошибку.

LocalDate.MAX.plusDays(1);

Результат:

DateTimeException

Это предотвращает скрытые ошибки вычислений.


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

Тип Instant представляет точку времени относительно UTC.

Создание

const { Instant } = require('@js-joda/core');

const instant = Instant.now();

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

Диапазон также ограничен:

Instant.MIN
Instant.MAX

Попытка выйти за пределы вызывает исключение.


Потеря точности при преобразованиях

Особое внимание требуется при конвертации между:

  • Instant;
  • Date;
  • timestamp;
  • JSON;
  • SQL.

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

const date = new Date();

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

Instant.ofEpochMilli(date.getTime());

наносекундная часть теряется.

Пример

const instant = Instant.parse(
  '2025-01-01T10:15:30.123456789Z'
);

console.log(instant.toEpochMilli());

Результат:

1735726530123

Сохраняются только миллисекунды.


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

Формат JSON не содержит встроенного типа даты.

Обычно используется ISO-строка:

{
  "createdAt": "2025-01-01T10:15:30.123456789Z"
}

Однако:

  • некоторые системы обрезают дробную часть;
  • некоторые БД поддерживают только миллисекунды;
  • часть API округляет значения.

Проблемы IEEE 754

JavaScript использует тип Number, основанный на IEEE 754.

Из-за этого возможны ограничения при работе с большими timestamp.

Пример

Number.MAX_SAFE_INTEGER

Безопасный диапазон целых чисел ограничен:

9007199254740991

Это влияет на:

  • epoch nanoseconds;
  • сверхдальние даты;
  • высокоточную арифметику времени.

Ограничения epoch nanoseconds

Хранение времени в наносекундах как одного числа небезопасно:

const nanos =
  1735726530123456789;

Такое значение может потерять точность.

Поэтому js-joda использует:

  • секунды;
  • наносекундную часть отдельно.

Это повторяет архитектуру Java Time API.


Ограничения часовых поясов

Для полноценной работы с временными зонами требуется:

@js-joda/timezone

Без этого доступны только:

  • UTC;
  • системная зона.

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

Не каждая строка является корректной зоной.

Пример

ZoneId.of('Mars/Base1');

Результат:

DateTimeException

DST и неоднозначное время

Переходы летнего времени создают сложные ситуации.

Несуществующее время

2025-03-30 02:30

В некоторых зонах такого времени не существует.

Дублирующееся время

Осенью один и тот же локальный момент может встречаться дважды.


Работа ZonedDateTime с DST

const zoned =
  ZonedDateTime.parse(
    '2025-10-26T02:30+02:00[Europe/Berlin]'
  );

Необходимо учитывать:

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

Исторические ограничения временных зон

База временных зон IANA периодически обновляется.

Следствия:

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

Ограничения производительности

Высокая точность имеет цену.

Операции js-joda обычно:

  • медленнее простого Date;
  • создают больше объектов;
  • используют сложную арифметику.

Неизменяемость и нагрузка на память

Каждая операция создаёт новый объект.

Пример

const next =
  date.plusDays(1);

Исходный объект не изменяется.

Преимущества:

  • безопасность;
  • отсутствие побочных эффектов;
  • потокобезопасность.

Недостатки:

  • дополнительные аллокации памяти;
  • нагрузка на GC.

Ограничения сериализации

Некоторые типы нельзя напрямую сериализовать.

Пример

JSON.stringify({
  date: LocalDate.now()
});

Результат зависит от реализации объекта.

Чаще используется явное преобразование:

date.toString()

Ограничения парсинга

Формат даты должен строго соответствовать шаблону.

Ошибка формата

LocalDate.parse('01-12-2025');

Результат:

DateTimeParseException

Строгость ISO-8601

По умолчанию библиотека ориентирована на ISO-8601.

Корректный формат:

2025-12-01

Некорректный:

01/12/2025

Ограничения кастомных форматов

Для сложного форматирования требуется пакет:

@js-joda/locale

Без него возможности форматирования ограничены.


Ограничения Temporal Precision Drift

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

Пример проблемы

setInterval(() => {
  // дрейф таймера
}, 1000);

js-joda не устраняет ограничения JavaScript timers:

  • задержки event loop;
  • блокировки потока;
  • неточность scheduler;
  • throttling браузера.

Монотонное и системное время

Системное время может:

  • изменяться вручную;
  • синхронизироваться NTP;
  • прыгать назад;
  • прыгать вперёд.

Для измерения интервалов предпочтительнее:

  • performance.now();
  • монотонные таймеры.

Instant.now() отражает именно системное время.


Ограничения leap seconds

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

Невозможное время

23:59:60

Такое значение считается некорректным.


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

js-joda использует:

  • ISO-8601;
  • пролептический григорианский календарь.

Не поддерживаются:

  • исламский календарь;
  • еврейский календарь;
  • китайский календарь;
  • другие календарные системы.

Ограничения совместимости

Некоторые сторонние библиотеки ожидают объект Date.

Поэтому может потребоваться конвертация:

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

При этом теряются:

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

Ограничения браузерной среды

Поддержка зависит от:

  • Intl API;
  • ICU;
  • timezone data;
  • версии движка JavaScript.

В старых окружениях возможны:

  • неверные зоны;
  • устаревшие DST;
  • проблемы форматирования.

Ограничения Node.js

Разные версии Node.js содержат:

  • разные timezone databases;
  • разные ICU сборки;
  • разные уровни поддержки Intl.

Из-за этого один и тот же код может выдавать различные результаты на разных серверах.


Ошибки округления при конвертации

Пример

const millis =
  instant.toEpochMilli();

Значение:

2025-01-01T10:15:30.123999999Z

после преобразования станет:

2025-01-01T10:15:30.123Z

Точность необратимо теряется.


Безопасная стратегия хранения времени

Для высокоточных систем обычно используются:

ISO-8601 строки

2025-01-01T10:15:30.123456789Z

Отдельные поля

{
  epochSecond: 1735726530,
  nano: 123456789
}

UTC-хранение

Все значения сохраняются в UTC, а локальная зона применяется только на уровне отображения.


Ограничения сравнения объектов

Объекты нельзя сравнивать оператором ===.

Неверно

date1 === date2

Правильно

date1.equals(date2)

или:

date1.compareTo(date2)

Ограничения математических операций

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

Пример

date.plus(1);

Некорректно.

Необходимо:

date.plusDays(1);

или:

date.plus(1, ChronoUnit.DAYS);

Ограничения интервалов

Тип Duration хранит:

  • секунды;
  • наносекунды.

Тип Period хранит:

  • годы;
  • месяцы;
  • дни.

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

Пример различия

Period.ofMonths(1)

не эквивалентен:

Duration.ofDays(30)

Поскольку месяцы имеют разную длину.


Точность вычислений Duration

Duration обеспечивает высокую точность интервалов.

1 =1,000,000,000 

Пример:

const duration =
  Duration.ofNanos(1);

Однако фактическая точность исполнения зависит от платформы выполнения JavaScript.


Ограничения при работе с базами данных

Многие СУБД ограничивают точность:

СУБД Точность
PostgreSQL микросекунды
MySQL миллисекунды/микросекунды
SQLite часто строки
MongoDB миллисекунды

При сохранении объектов js-joda часть данных может теряться.


Типичные ошибки при работе с точностью

Смешивание локального и UTC времени

LocalDateTime.now()

и:

Instant.now()

представляют разные концепции.


Использование Date для высокоточных вычислений

new Date().getTime()

не подходит для наносекундных операций.


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

Добавление суток:

plusDays(1)

не всегда означает:

24 часа

из-за переходов времени.


Хранение timestamp в Number

Большие значения могут терять точность.

Безопаснее:

  • строки;
  • BigInt;
  • раздельное хранение seconds/nanos.