Разница между датами в работе с календарными системами требует
строгого разделения понятий «календарный интервал» и «временная
длительность». В экосистеме js-joda эти концепции реализованы через
разные типы и функции: Period, Duration, а
также утилиты ChronoUnit и методы between /
until.
Вся модель расчётов опирается на различие типов:
LocalDate — дата без времени и часового поясаLocalDateTime — дата и время без часового поясаZonedDateTime — дата и время с часовым поясомInstant — абсолютная точка времени в UTCРазница между датами интерпретируется по-разному в зависимости от используемого типа.
Period применяется для вычисления разницы в календарных
единицах: годы, месяцы, дни. Он учитывает структуру календаря, а не
фиксированное количество времени.
import { LocalDate, Period } from '@js-joda/core';
const start = LocalDate.parse('2020-01-15');
const end = LocalDate.parse('2023-04-10');
const period = Period.between(start, end);
Объект period содержит:
Ключевая особенность: разложение происходит по календарным границам, а не через общее количество дней.
При расчётах учитывается фактическая длина месяцев:
const a = LocalDate.parse('2023-01-31');
const b = LocalDate.parse('2023-03-01');
const p = Period.between(a, b);
Результат будет зависеть от нормализации календарных переходов, а не от фиксированного количества дней.
Duration оперирует абсолютным временем, измеряемым в
секундах и наносекундах. Он используется для Instant,
LocalDateTime, ZonedDateTime.
import { LocalDateTime, Duration } from '@js-joda/core';
const start = LocalDateTime.parse('2023-01-01T10:00:00');
const end = LocalDateTime.parse('2023-01-01T12:30:00');
const duration = Duration.between(start, end);
Результат:
duration.toHours(); // 2
duration.toMinutes(); // 150
duration.getSeconds(); // 9000
Duration всегда выражается как точное количество времени
без календарной логики.
ChronoUnit предоставляет более низкоуровневый способ
вычисления разницы между датами.
import { LocalDate, ChronoUnit } from '@js-joda/core';
const start = LocalDate.parse('2023-01-01');
const end = LocalDate.parse('2023-01-10');
const days = ChronoUnit.DAYS.between(start, end);
Результат: 9
ChronoUnit.MONTHS.between(start, end);
ChronoUnit.YEARS.between(start, end);
ChronoUnit.WEEKS.between(start, end);
Каждая единица вычисляется по собственным правилам календарной нормализации.
Многие классы предоставляют метод until, который
возвращает разницу до другой даты.
const start = LocalDate.parse('2023-01-01');
const end = LocalDate.parse('2023-01-10');
const days = start.until(end, ChronoUnit.DAYS);
Поведение эквивалентно
ChronoUnit.DAYS.between(start, end), но с инверсией порядка
вызова.
При работе с часовыми поясами учитываются переходы на летнее/зимнее время.
import { ZonedDateTime, Duration, ZoneId } from '@js-joda/core';
const zone = ZoneId.of('Europe/Berlin');
const start = ZonedDateTime.of(
2023, 3, 25, 10, 0, 0, 0, zone
);
const end = ZonedDateTime.of(
2023, 3, 26, 10, 0, 0, 0, zone
);
const duration = Duration.between(start, end);
Несмотря на одинаковый «локальный интервал» в 24 часа, фактическая длительность может отличаться из-за перехода времени.
| Характеристика | Period | Duration |
|---|---|---|
| Единицы | годы, месяцы, дни | секунды, наносекунды |
| Основа | календарь | абсолютное время |
| Часовые пояса | игнорируются | учитываются |
| Типы | LocalDate | Instant, LocalDateTime |
Для точного анализа часто применяется последовательное использование разных подходов.
const startDate = LocalDate.parse('2020-01-01');
const endDate = LocalDate.parse('2023-03-15');
const period = Period.between(startDate, endDate);
const days = ChronoUnit.DAYS.between(startDate, endDate);
Period даёт структуру (годы/месяцы/дни), а
ChronoUnit — общее количество дней.
При переходе между единицами происходит автоматическая нормализация:
Duration.between(LocalDate.parse('2023-01-01'), LocalDate.parse('2023-01-10'));
Такой вызов некорректен, так как Duration требует
временных типов.
Разница между двумя LocalDateTime не учитывает
фактические смещения зоны.
ChronoUnit.DAYS.between(
LocalDate.parse('2023-02-01'),
LocalDate.parse('2023-03-01')
);
Результат зависит от календарного месяца, а не фиксированного интервала.
import { Instant, ZoneId } from '@js-joda/core';
const instant = Instant.now();
const zoned = instant.atZone(ZoneId.of('UTC'));
После преобразования можно применять Duration для точных
вычислений.
Period — анализ жизненных интервалов (возраст, стаж,
календарные периоды)Duration — измерение времени выполнения, задержек,
тайминговChronoUnit — быстрые скалярные вычисления между
датамиuntil — синтаксический сахар над
ChronoUnit