js-joda

Библиотека js-joda реализует подход к работе со временем, основанный на Java Time (java.time). Ключевая особенность — полная иммутабельность объектов: каждая операция над датой или временем возвращает новый экземпляр, не изменяя исходный.

Такой подход устраняет целый класс ошибок, характерных для стандартного Date в JavaScript, где изменения объекта могут приводить к непредсказуемым побочным эффектам.

Иммутабельность означает:

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

Основные типы данных

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

LocalDate

LocalDate представляет календарную дату без времени и часового пояса.

Используется для:

  • дат рождения
  • расписаний
  • бизнес-логики, не зависящей от времени суток

Пример:

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

const date = LocalDate.of(2026, 5, 23);
const nextDay = date.plusDays(1);

Операция plusDays не изменяет исходный объект, а создаёт новый.


LocalTime

LocalTime описывает время без даты и без часового пояса.

Используется для:

  • расписаний (например, “09:00”)
  • таймеров внутри дня
  • временных интервалов без привязки к календарю
import { LocalTime } from '@js-joda/core';

const time = LocalTime.of(14, 30);
const later = time.plusHours(2);

LocalDateTime

LocalDateTime объединяет дату и время, но не содержит информации о часовом поясе.

Подходит для:

  • локальных событий
  • хранения “человеческого времени”
  • промежуточных вычислений
import { LocalDateTime } from '@js-joda/core';

const dt = LocalDateTime.of(2026, 5, 23, 10, 15);
const updated = dt.plusMinutes(45);

Instant

Instant представляет точку на временной шкале в формате UTC.

Используется для:

  • меток времени (timestamps)
  • логирования
  • синхронизации систем
import { Instant } from '@js-joda/core';

const now = Instant.now();
const later = now.plusSeconds(60);

ZonedDateTime

ZonedDateTime объединяет дату, время и часовой пояс.

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

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

const zdt = ZonedDateTime.now(ZoneId.of('Europe/Paris'));
const converted = zdt.withZoneSameInstant(ZoneId.of('UTC'));

Особенность: изменение зоны не меняет момент времени, а пересчитывает отображение.


Продолжительность и периоды

Duration

Duration измеряет точное время в секундах и наносекундах.

Используется для:

  • измерения производительности
  • таймеров
  • вычисления разницы между Instant
import { Duration, Instant } from '@js-joda/core';

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

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

Period

Period работает с календарными единицами: годами, месяцами, днями.

Используется для:

  • возраста
  • подписок
  • календарных интервалов
import { Period } from '@js-joda/core';

const period = Period.of(1, 2, 10); // 1 год, 2 месяца, 10 дней

Арифметика дат

Все типы поддерживают единый набор методов:

  • plusDays, plusMonths, plusYears
  • minusDays, minusHours
  • withDayOfMonth, withYear

Принцип работы:

  1. исходный объект не изменяется
  2. возвращается новый экземпляр
  3. операции можно цепочить
const result = LocalDate
  .of(2026, 1, 1)
  .plusMonths(1)
  .minusDays(2)
  .withDayOfMonth(10);

Сравнение дат

Для сравнения используются методы:

  • isBefore
  • isAfter
  • isEqual
const a = LocalDate.of(2026, 5, 1);
const b = LocalDate.of(2026, 5, 23);

const check = a.isBefore(b);

Сравнение строго типизировано: нельзя случайно сравнить LocalDate и LocalTime.


Парсинг и форматирование

js-joda использует отдельный механизм форматирования через DateTimeFormatter.

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

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

const formatter = DateTimeFormatter.ofPattern('dd.MM.yyyy');
const text = LocalDate.of(2026, 5, 23).format(formatter);

Парсинг

const parsed = LocalDate.parse('23.05.2026', formatter);

Преимущество подхода:

  • строгая типизация форматов
  • отсутствие неявных преобразований
  • единообразие между типами

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

Часовые пояса в js-joda представлены через ZoneId.

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

  • поддержка IANA time zones
  • корректная обработка переходов DST
  • явное управление конверсией времени
import { ZoneId } from '@js-joda/core';

const zone = ZoneId.of('Asia/Almaty');

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

Типичная цепочка преобразований:

  • InstantZonedDateTime (через зону)
  • ZonedDateTimeLocalDateTime (с потерей зоны)
  • LocalDateTimeInstant (через указание зоны)
const instant = Instant.now();

const zoned = instant.atZone(ZoneId.of('UTC'));
const local = zoned.toLocalDateTime();

Сопоставление с подходом Day.js

В библиотеке Day.js используется другой философский подход:

  • работа через единый объект-обёртку
  • частичная мутабельность через цепочки вызовов
  • ориентир на минимальный размер и простоту API
  • расширение функциональности через плагины

js-joda, напротив:

  • строго типизированная модель времени
  • разделение на специализированные классы
  • отсутствие глобального объекта даты
  • поведение, приближенное к языковым стандартам Java

Отличия от стандартного Date

Стандартный Date в JavaScript имеет ряд ограничений:

  • мутабельность внутренних значений
  • неоднозначное поведение при парсинге строк
  • смешивание UTC и локального времени
  • отсутствие типов для разных уровней времени (дата/время/момент)

js-joda решает это через:

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

Обработка временных интервалов в бизнес-логике

Использование Period и Duration позволяет разделять:

  • календарную логику (месяцы, годы)
  • точные интервалы (секунды, миллисекунды)

Пример бизнес-логики подписки:

const start = LocalDate.now();
const end = start.plusMonths(1);

const isActive = LocalDate.now().isBefore(end);

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


Модель проектирования времени

Архитектурно js-joda опирается на несколько принципов:

  • разделение представлений времени
  • явная работа с контекстом (зона, локаль, момент)
  • отсутствие скрытых преобразований
  • композиция объектов вместо мутаций

Эта модель хорошо подходит для:

  • финансовых систем
  • распределённых сервисов
  • систем расписаний
  • логирования событий

Обработка пограничных случаев времени

Особое внимание уделяется:

  • переходам на летнее/зимнее время
  • неоднозначным локальным датам
  • различию между “моментом” и “отображением”

Пример:

const zdt = LocalDateTime.of(2026, 3, 29, 2, 30)
  .atZone(ZoneId.of('Europe/Berlin'));

Такие случаи требуют явного разрешения через правила зоны, что исключает неоднозначность.


Использование в масштабируемых приложениях

js-joda особенно эффективна в системах, где требуется:

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

Иммутабельная модель позволяет безопасно:

  • кэшировать даты
  • передавать объекты между потоками
  • использовать чистые функции для расчётов времени