Модуль TemporalAdjusters представляет собой набор
предопределённых и расширяемых стратегий преобразования дат и времени.
Его задача — выполнять нетривиальные календарные операции, которые
невозможно выразить простой арифметикой добавления дней, месяцев или
лет.
В основе концепции лежит идея коррекции временной точки (Temporal Adjustment): исходная дата преобразуется в новую по заданному правилу, зависящему от календарной логики, а не от фиксированного смещения.
TemporalAdjusters реализует функциональный подход:
каждый корректировщик — это функция, принимающая объект типа
Temporal и возвращающая новый Temporal.
Ключевая особенность:
with(...)Базовая сигнатура:
TemporalAdjuster = (temporal) => Temporal
Использование:
import { LocalDate, TemporalAdjusters } from '@js-joda/core';
const date = LocalDate.parse('2026-01-15');
const adjusted = date.with(TemporalAdjusters.firstDayOfMonth());
Одна из самых используемых групп — вычисление границ календарных интервалов.
TemporalAdjusters.firstDayOfMonth()
Поведение:
1Пример:
LocalDate.parse('2026-05-25')
.with(TemporalAdjusters.firstDayOfMonth());
// 2026-05-01
TemporalAdjusters.lastDayOfMonth()
Логика учитывает:
LocalDate.parse('2024-02-10')
.with(TemporalAdjusters.lastDayOfMonth());
// 2024-02-29
TemporalAdjusters.firstDayOfYear()
Результат всегда:
TemporalAdjusters.lastDayOfYear()
Работа с днями недели — одна из ключевых задач календарных систем.
TemporalAdjusters.next(DayOfWeek.MONDAY)
Логика:
import { DayOfWeek, LocalDate, TemporalAdjusters } from '@js-joda/core';
LocalDate.parse('2026-05-25')
.with(TemporalAdjusters.next(DayOfWeek.FRIDAY));
TemporalAdjusters.nextOrSame(DayOfWeek.MONDAY)
Отличие:
TemporalAdjusters.previous(DayOfWeek.SUNDAY)
Поведение:
TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY)
TemporalAdjusters позволяет выражать сложные правила бизнес-календарей.
Хотя есть firstDayOfMonth, можно комбинировать с
логикой:
date.with(TemporalAdjusters.firstDayOfMonth())
Но важно, что корректировщики можно использовать в цепочках.
В стандартной библиотеке нет прямого firstDayOfQuarter,
но он легко реализуется:
const firstDayOfQuarter = (temporal) => {
const month = temporal.monthValue();
const startMonth = month <= 3 ? 1 : month <= 6 ? 4 : month <= 9 ? 7 : 10;
return temporal.withMonth(startMonth).withDayOfMonth(1);
};
Использование:
LocalDate.parse('2026-08-15')
.with(firstDayOfQuarter);
// 2026-07-01
Ключевая сила механизма — возможность создавать собственные корректировщики.
const customAdjuster = (temporal) => {
return temporal.plusDays(10);
};
Использование:
date.with(customAdjuster);
const nextWorkingFriday = (temporal) => {
let result = temporal.with(TemporalAdjusters.nextOrSame(DayOfWeek.FRIDAY));
if (result.dayOfWeek().equals(DayOfWeek.SATURDAY)) {
result = result.with(TemporalAdjusters.next(DayOfWeek.FRIDAY));
}
return result;
};
const lastWorkingDayOfMonth = (temporal) => {
let result = temporal.with(TemporalAdjusters.lastDayOfMonth());
const dayOfWeek = result.dayOfWeek();
if (dayOfWeek.equals(DayOfWeek.SATURDAY)) {
result = result.minusDays(1);
}
if (dayOfWeek.equals(DayOfWeek.SUNDAY)) {
result = result.minusDays(2);
}
return result;
};
Корректировщики можно применять последовательно, формируя цепочки преобразований.
date
.with(TemporalAdjusters.firstDayOfMonth())
.with(TemporalAdjusters.next(DayOfWeek.MONDAY));
Логика:
TemporalAdjusters применяется ко всем типам, реализующим
интерфейс Temporal, включая:
LocalDateLocalDateTimeZonedDateTimeОсобенность:
ZonedDateTime сохраняется временная
зонаLocalDateTime сохраняются компоненты
времениПример:
import { ZonedDateTime, TemporalAdjusters, DayOfWeek } from '@js-joda/core';
const zdt = ZonedDateTime.now();
const adjusted = zdt.with(TemporalAdjusters.next(DayOfWeek.MONDAY));
TemporalAdjusters учитывает:
Пример критического случая:
LocalDate.parse('2024-01-31')
.with(TemporalAdjusters.firstDayOfMonth());
Результат корректно:
2024-01-01
Модель работы TemporalAdjusters построена на принципах:
Это обеспечивает:
На практике TemporalAdjusters часто используется как базовый слой доменной календарной логики.
Пример слоя правил:
const BusinessCalendar = {
startOfMonth: (d) => d.with(TemporalAdjusters.firstDayOfMonth()),
endOfMonth: (d) => d.with(TemporalAdjusters.lastDayOfMonth()),
nextWorkingDay: (d) => d.with(TemporalAdjusters.next(DayOfWeek.MONDAY)),
};
Несмотря на гибкость, существуют ограничения:
Эти ограничения компенсируются возможностью создания пользовательских корректировщиков.
TemporalAdjusters реализует абстракцию:
“Дата не изменяется напрямую — она пересчитывается относительно правила”
Это отличает подход от императивных моделей:
setDateКаждое преобразование является чистой функцией, зависящей только от входной временной точки и логики корректировки