Fluent interface в js-joda основан на цепочках вызовов методов, возвращающих новые неизменяемые экземпляры временных объектов. Каждый вызов трансформации не модифицирует исходное значение, а создаёт новый объект с применёнными изменениями. Это формирует выразительный стиль работы с датами и временем, в котором последовательность операций читается как единое выражение.
Ключевая особенность заключается в том, что все временные типы
библиотеки — LocalDate, LocalTime,
LocalDateTime, ZonedDateTime,
Instant — спроектированы как immutable-объекты. Fluent
interface становится естественным следствием этой модели.
Fluent API в js-joda строится вокруг идеи последовательного преобразования состояния:
LocalDate.now()
.plusDays(5)
.minusMonths(2)
.plusYears(1)
Каждый метод возвращает новый объект того же типа, что позволяет продолжать цепочку без промежуточных переменных.
Такой стиль исключает необходимость временных переменных и снижает вероятность ошибок, связанных с изменением состояния.
В отличие от классических Date API, где операции часто изменяют объект, js-joda гарантирует неизменяемость:
const date = LocalDate.of(2024, 1, 10);
const updated = date.plusDays(10);
date.toString(); // 2024-01-10
updated.toString(); // 2024-01-20
Fluent интерфейс опирается на это поведение: каждое звено цепочки работает с новым значением, сохраняя предсказуемость вычислений.
Fluent interface позволяет строить сложные выражения из простых операций:
const result = LocalDate.now()
.plusWeeks(2)
.withDayOfMonth(1)
.minusDays(1);
Здесь последовательно применяются:
Каждый шаг возвращает новый LocalDate, который сразу
используется следующим методом.
Для LocalTime цепочки аналогичны, но оперируют
временными компонентами:
const time = LocalTime.of(10, 30)
.plusHours(3)
.plusMinutes(45)
.minusSeconds(10);
Такая композиция удобна при построении расписаний и вычислении временных окон.
LocalDateTime объединяет оба контекста и поддерживает
более сложные цепочки:
const dt = LocalDateTime.now()
.plusDays(1)
.plusHours(2)
.withMinute(0)
.withSecond(0);
Fluent интерфейс здесь позволяет формировать нормализованные временные метки, например, для начала событий или дедлайнов.
ZonedDateTime добавляет слой временной зоны, но
сохраняет тот же стиль цепочек:
const zoned = ZonedDateTime.now()
.plusDays(1)
.withZoneSameInstant(ZoneId.of("Europe/Berlin"))
.plusHours(2);
Методы делятся на две категории:
plusDays,
minusHours)withZoneSameInstant,
withZoneSameLocal)Fluent интерфейс позволяет комбинировать их в одном выражении без потери читаемости.
Методы with* являются ключевым элементом fluent API,
позволяя заменять отдельные компоненты:
const modified = LocalDate.now()
.withYear(2030)
.withMonth(12)
.withDayOfMonth(25);
Каждый вызов возвращает новый объект с изменённым полем, сохраняя остальные значения.
Fluent interface распространяется и на результаты парсинга строк:
const date = LocalDate.parse("2025-05-10")
.plusDays(10)
.minusMonths(1);
Парсинг создаёт начальный объект, после чего он участвует в цепочке преобразований без дополнительных шагов.
Fluent подход используется и при работе с промежутками времени:
const period = Period.ofMonths(2)
.plusWeeks(1)
.plusDays(3);
или для длительностей:
const duration = Duration.ofHours(5)
.plusMinutes(30)
.minusSeconds(15);
Каждый метод возвращает новый объект периода или длительности, поддерживая единый стиль API.
Instant представляет момент времени в UTC и поддерживает
fluent операции:
const instant = Instant.now()
.plusSeconds(60)
.plusMillis(500);
В отличие от локальных типов, здесь отсутствует календарная логика, но цепочки остаются идентичными по структуре.
Fluent interface позволяет формировать вложенные выражения, где результат одной цепочки используется как вход для другой:
const result = ZonedDateTime.now()
.plusDays(1)
.toLocalDate()
.atStartOfDay()
.plusHours(6);
Здесь происходит переход между типами:
ZonedDateTimeLocalDateLocalDateTimeКаждый переход сохраняет возможность продолжать цепочку методов.
Fluent API поддерживает симметричную работу с добавлением и вычитанием:
const adjusted = LocalDate.now()
.plusDays(10)
.minusDays(3)
.plusDays(1)
.minusMonths(2);
Такой стиль позволяет рассматривать временные вычисления как последовательность преобразований без промежуточных вычислительных переменных.
Некоторые операции автоматически нормализуют значения при переходах через границы:
const time = LocalTime.of(23, 50)
.plusMinutes(30);
Результат переносит значение на следующий день, сохраняя корректность модели времени. Fluent интерфейс скрывает эти детали за последовательностью методов.
Fluent стиль часто комбинируется с внешней логикой:
let result = LocalDate.now();
result = result.plusDays(5);
if (result.getDayOfWeek().equals(DayOfWeek.SATURDAY)) {
result = result.plusDays(2);
}
Хотя условные конструкции разрывают цепочку, базовый принцип остаётся тем же: каждое преобразование создаёт новый объект.
Один и тот же исходный объект может использоваться в нескольких независимых цепочках:
const base = LocalDate.of(2024, 6, 1);
const a = base.plusDays(10).plusMonths(1);
const b = base.minusDays(5).withYear(2025);
Fluent интерфейс в сочетании с immutable-моделью позволяет строить независимые вычислительные ветви.
Цепочки могут комбинироваться с функциями, возвращающими временные объекты:
const shift = (date) => date.plusDays(3).minusMonths(1);
const result = shift(LocalDate.now())
.plusYears(2)
.withDayOfMonth(15);
Fluent интерфейс остаётся совместимым с функциональным стилем, не нарушая композиционность.
Цепочки методов позволяют формировать декларативные конструкции:
const schedule = LocalDateTime.now()
.plusDays(7)
.withHour(9)
.withMinute(0)
.withSecond(0)
.withNano(0);
Каждый вызов уточняет итоговое состояние, постепенно приводя объект к нужной конфигурации.
Fluent API скрывает сложность календарных вычислений:
const date = LocalDate.of(2024, 1, 31)
.plusMonths(1);
Результат корректируется согласно правилам календаря, сохраняя согласованность цепочки вызовов без дополнительных проверок.
Fluent стиль js-joda унифицирует работу со всеми временными типами:
plus* — добавлениеminus* — вычитаниеwith* — замена компонентовto* — преобразование типовЭта структура делает переход между LocalDate,
LocalTime и ZonedDateTime предсказуемым и
симметричным.
Каждая цепочка представляет собой композицию функций:
f(g(h(x)))
но записанную в линейной форме:
x.h().g().f()
В js-joda этот принцип распространяется на все временные операции, создавая единый язык описания преобразований времени.