Библиотека Js-joda реализует API, основанный на концепциях Java Time API из Java 8. Арифметические операции в библиотеке строятся вокруг принципа неизменяемости объектов: любой вызов метода возвращает новый экземпляр даты или времени, не изменяя исходный объект.
Это особенно важно при работе со сложными вычислениями времени, цепочками операций и календарной логикой.
const { LocalDate } = require('@js-joda/core');
const date = LocalDate.parse('2025-05-10');
const nextDay = date.plusDays(1);
console.log(date.toString()); // 2025-05-10
console.log(nextDay.toString()); // 2025-05-11
Исходный объект date остаётся неизменным.
Для работы с календарными днями используются методы:
plusDays()minusDays()const { LocalDate } = require('@js-joda/core');
const date = LocalDate.of(2025, 1, 15);
console.log(date.plusDays(10).toString());
console.log(date.minusDays(5).toString());
Результат:
2025-01-25
2025-01-10
Js-joda автоматически корректно обрабатывает границы месяцев и лет.
const date = LocalDate.of(2025, 12, 28);
console.log(date.plusDays(10).toString());
Результат:
2026-01-07
const leap = LocalDate.of(2024, 2, 28);
console.log(leap.plusDays(1).toString());
console.log(leap.plusDays(2).toString());
Результат:
2024-02-29
2024-03-01
Библиотека автоматически учитывает календарные правила ISO-8601.
const { LocalDate } = require('@js-joda/core');
const date = LocalDate.of(2025, 1, 10);
console.log(date.plusMonths(2).toString());
Результат:
2025-03-10
Одной из ключевых особенностей библиотеки является автоматическая нормализация дат.
const date = LocalDate.of(2025, 1, 31);
console.log(date.plusMonths(1).toString());
Результат:
2025-02-28
Так как 31 февраля не существует, библиотека корректирует дату до последнего допустимого дня месяца.
const date = LocalDate.of(2025, 5, 15);
console.log(date.minusMonths(3).toString());
Результат:
2025-02-15
const { LocalDate } = require('@js-joda/core');
const date = LocalDate.of(2020, 6, 20);
console.log(date.plusYears(5).toString());
console.log(date.minusYears(2).toString());
Результат:
2025-06-20
2018-06-20
Особое внимание следует уделять високосным датам.
const leapDay = LocalDate.of(2024, 2, 29);
console.log(leapDay.plusYears(1).toString());
Результат:
2025-02-28
При переходе в невисокосный год библиотека корректирует дату автоматически.
Класс LocalTime предназначен для операций над временем
без даты.
const { LocalTime } = require('@js-joda/core');
const time = LocalTime.of(10, 30);
console.log(time.plusHours(5).toString());
console.log(time.minusMinutes(15).toString());
Результат:
15:30
10:15
const time = LocalTime.of(23, 30);
console.log(time.plusHours(2).toString());
Результат:
01:30
Время циклически переходит через полночь.
const time = LocalTime.of(12, 0, 30);
console.log(time.plusSeconds(45).toString());
console.log(time.plusNanos(1000).toString());
Класс LocalDateTime объединяет дату и время.
const { LocalDateTime } = require('@js-joda/core');
const dt = LocalDateTime.of(2025, 5, 10, 14, 30);
console.log(dt.plusDays(2).plusHours(3).toString());
Результат:
2025-05-12T17:30
Благодаря неизменяемости объектов можно безопасно выстраивать длинные последовательности вычислений.
const result = LocalDateTime.now()
.plusYears(1)
.minusMonths(2)
.plusDays(15)
.minusHours(4);
console.log(result.toString());
Для универсальной арифметики применяется метод
plus().
const {
LocalDate,
ChronoUnit
} = require('@js-joda/core');
const date = LocalDate.of(2025, 1, 1);
const result = date.plus(10, ChronoUnit.DAYS);
console.log(result.toString());
Наиболее распространённые значения ChronoUnit:
DAYSWEEKSMONTHSYEARSHOURSMINUTESSECONDSNANOSПример:
const result = date.plus(2, ChronoUnit.WEEKS);
Метод minus() работает аналогично
plus().
const result = date.minus(3, ChronoUnit.MONTHS);
Класс Period используется для хранения периодов в годах,
месяцах и днях.
const { Period } = require('@js-joda/core');
const period = Period.of(1, 2, 15);
console.log(period.toString());
Результат:
P1Y2M15D
const {
LocalDate,
Period
} = require('@js-joda/core');
const date = LocalDate.of(2025, 1, 10);
const period = Period.ofMonths(3);
console.log(date.plus(period).toString());
Результат:
2025-04-10
const period = Period.of(2, 5, 10);
const result = date.plus(period);
console.log(result.toString());
Duration хранит интервалы времени в секундах и
наносекундах.
const { Duration } = require('@js-joda/core');
const duration = Duration.ofHours(5);
console.log(duration.toString());
Результат:
PT5H
const {
LocalDateTime,
Duration
} = require('@js-joda/core');
const dt = LocalDateTime.now();
const result = dt.plus(Duration.ofMinutes(90));
console.log(result.toString());
Используется для:
Учитывает календарные особенности.
Period.ofMonths(1)
Используется для:
Работает как точный временной интервал.
Duration.ofHours(24)
const {
LocalDate,
ChronoUnit
} = require('@js-joda/core');
const start = LocalDate.of(2025, 1, 1);
const end = LocalDate.of(2025, 2, 1);
console.log(start.until(end, ChronoUnit.DAYS));
Результат:
31
console.log(start.until(end, ChronoUnit.MONTHS));
Результат:
1
const {
LocalTime,
Duration
} = require('@js-joda/core');
const start = LocalTime.of(10, 0);
const end = LocalTime.of(12, 30);
const duration = Duration.between(start, end);
console.log(duration.toString());
Результат:
PT2H30M
Js-joda поддерживает отрицательные значения во всех арифметических методах.
const date = LocalDate.of(2025, 5, 10);
console.log(date.plusDays(-5).toString());
Результат:
2025-05-05
const date = LocalDate.of(2025, 1, 1);
console.log(date.plusWeeks(3).toString());
console.log(date.minusWeeks(1).toString());
Для операций с часовыми поясами используется
ZonedDateTime.
const {
ZonedDateTime,
ZoneId
} = require('@js-joda/core');
const zdt = ZonedDateTime.now(ZoneId.of('Asia/Almaty'));
console.log(zdt.plusHours(5).toString());
Js-joda корректно обрабатывает DST-переходы при наличии timezone-модуля.
const {
ZonedDateTime,
LocalDateTime,
ZoneId
} = require('@js-joda/core');
const dt = LocalDateTime.of(2025, 3, 30, 1, 30);
const zoned = ZonedDateTime.of(
dt,
ZoneId.of('Europe/Berlin')
);
console.log(zoned.plusHours(2).toString());
Иногда требуется не прибавление значения, а замена конкретного поля.
const date = LocalDate.of(2025, 5, 10);
console.log(date.withMonth(12).toString());
Результат:
2025-12-10
const d1 = LocalDate.of(2025, 1, 1);
const d2 = d1.plusDays(10);
console.log(d2.isAfter(d1));
console.log(d1.isBefore(d2));
Неверный подход:
let date = LocalDate.now();
date.plusDays(1);
console.log(date);
Дата не изменится.
date = date.plusDays(1);
Js-joda оптимизирована для большого количества вычислений и
значительно безопаснее встроенного объекта Date при сложной
календарной логике:
const expiresAt = LocalDateTime.now()
.plusMinutes(30);
const subscriptionEnd = LocalDate.now()
.plusMonths(1);
const birthDate = LocalDate.of(1995, 6, 10);
const age = birthDate.until(
LocalDate.now(),
ChronoUnit.YEARS
);
console.log(age);
const meeting = ZonedDateTime.now(
ZoneId.of('Asia/Almaty')
).plusWeeks(2).withHour(15).withMinute(0);