Переход с Day.js

Переход с Day.js на js-joda связан не только со сменой библиотеки, но и с изменением подхода к работе с датой и временем.

Day.js — лёгкая библиотека, ориентированная на совместимость с Moment.js и цепочечный API. js-joda — порт Java Time API (java.time), основанный на строгой модели календарных сущностей и иммутабельности.

Ключевое отличие заключается в философии:

  • Day.js: гибкий объект даты с расширяемыми плагинами
  • js-joda: строго типизированные классы времени и календаря

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

Day.js

В Day.js используется единый объект-обёртка:

  • dayjs() возвращает объект-обёртку над Date
  • операции часто возвращают новый Day.js объект
  • поведение расширяется плагинами

js-joda

js-joda разделяет концепции:

  • LocalDate — дата без времени
  • LocalTime — время без даты
  • LocalDateTime — дата и время без зоны
  • ZonedDateTime — дата и время с временной зоной
  • Instant — точка времени в UTC

Ключевой принцип: каждая сущность строго определена и не смешивает ответственность.


Иммутабельность и предсказуемость

Обе библиотеки иммутабельны, но в js-joda это фундаментальная гарантия:

  • Любая операция создаёт новый объект
  • Исходный объект никогда не изменяется
  • API исключает скрытые мутации

В Day.js иммутабельность также соблюдается, но:

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

В js-joda иммутабельность встроена в модель языка библиотеки.


Создание и базовые операции

Day.js

import dayjs from 'dayjs';

const date = dayjs();
const parsed = dayjs('2026-01-01');
const modified = date.add(5, 'day');

js-joda

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

const date = LocalDate.now();
const parsed = LocalDate.parse('2026-01-01');
const modified = date.plusDays(5);

Различие в арифметике дат

Day.js

  • единый метод add(value, unit)
  • единый метод subtract(value, unit)
dayjs().add(2, 'month');
dayjs().subtract(10, 'day');

js-joda

  • строго типизированные методы
  • отдельные функции для каждой единицы
date.plusMonths(2);
date.minusDays(10);

Ключевое отличие: отсутствие строковых единиц измерения в js-joda.


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

Day.js

Гибкий парсинг:

dayjs('2026-01-01');
dayjs('01/01/2026', 'DD/MM/YYYY');

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

dayjs().format('YYYY-MM-DD');

js-joda

Парсинг строго ISO-форматированный:

LocalDate.parse('2026-01-01');

Форматирование требует отдельного форматтера:

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

const formatter = DateTimeFormatter.ofPattern('dd.MM.yyyy');
date.format(formatter);

Ключевое отличие: отсутствие неявного парсинга и глобальных форматов.


Временные зоны

Day.js

Поддержка через плагины:

  • utc
  • timezone
import utc from 'dayjs/plugin/utc';
import timezone from 'dayjs/plugin/timezone';

js-joda

Отдельный модуль:

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

const zdt = ZonedDateTime.now(ZoneId.of('Europe/Berlin'));

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

  • зоны — полноценные сущности
  • строгая работа с DST (летнее время)
  • отсутствие скрытых преобразований

Сравнение API концепций

Операция Day.js js-joda
текущая дата dayjs() LocalDate.now()
парсинг dayjs(str) LocalDate.parse(str)
прибавить дни .add(1, 'day') .plusDays(1)
форматирование .format() formatter.format()
UTC plugin Instant

Работа с временем: типичные различия

1. Отсутствие “магического Date”

Day.js частично опирается на Date:

  • возможны особенности поведения JS Date
  • различия окружений (браузер/Node)

js-joda:

  • собственная модель времени
  • отсутствие зависимости от Date в логике

2. Разделение понятий даты и времени

Day.js:

  • один объект для всего

js-joda:

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

Это устраняет ошибки вида:

  • сравнение даты и времени без учёта зоны
  • смешивание локального и UTC контекста

Переходная стратегия миграции

1. Выделение всех точек работы с датой

Типичные места:

  • сервисы API
  • работа с бэкенд-ответами
  • форматирование UI

2. Замена Day.js на js-joda по слоям

Рекомендуемая последовательность:

  1. Парсинг входных данных
  2. Внутренние вычисления
  3. Форматирование
  4. UI слой

3. Маппинг типов

Day.js → js-joda:

  • dayjs()LocalDateTime.now() или Instant.now()
  • add('day')plusDays()
  • format()DateTimeFormatter

Типичные ошибки при миграции

1. Ожидание гибкого парсинга

LocalDate.parse('01/01/2026'); // ошибка

js-joda требует ISO или форматтера.


2. Потеря временной зоны

Day.js:

dayjs().tz('Asia/Almaty')

js-joda:

ZonedDateTime.now(ZoneId.of('Asia/Almaty'))

3. Использование строковых единиц

date.plus('day') // не существует

В js-joda только строго типизированные методы.


Работа с календарной логикой

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

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

Day.js в большей степени опирается на JavaScript Date и плагины.


Производительность и предсказуемость

js-joda:

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

Day.js:

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

Итоговое сопоставление подходов

Day.js ориентирован на:

  • быстрый старт
  • лаконичный API
  • совместимость с Moment.js

js-joda ориентирован на:

  • строгую модель времени
  • отсутствие неоднозначностей
  • архитектурную надёжность в сложных системах

Пример эквивалентной логики

Day.js

const result = dayjs()
  .add(7, 'day')
  .format('YYYY-MM-DD');

js-joda

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

const formatter = DateTimeFormatter.ofPattern('yyyy-MM-dd');

const result = LocalDate.now()
  .plusDays(7)
  .format(formatter);