Библиотека js-joda предоставляет строгую и предсказуемую модель работы с датой и временем. Одной из ключевых задач при работе с временными типами является корректное сравнение значений: проверка равенства, определение порядка дат, вычисление временных интервалов и анализ пересечений диапазонов.
В отличие от стандартного объекта Date, сравнение в
Js-joda построено на неизменяемых типах и строгой типизации временных
сущностей.
Перед сравнением необходимо понимать, какие типы данных участвуют в операции.
| Тип | Назначение |
|---|---|
LocalDate |
Только дата |
LocalTime |
Только время |
LocalDateTime |
Дата и время без часового пояса |
ZonedDateTime |
Дата и время с часовым поясом |
Instant |
Момент времени в UTC |
Duration |
Интервал времени |
Period |
Интервал дат |
Каждый тип поддерживает собственные методы сравнения.
Метод equals() проверяет полное совпадение объектов.
const { LocalDate } = require('@js-joda/core');
const d1 = LocalDate.parse('2025-03-10');
const d2 = LocalDate.parse('2025-03-10');
console.log(d1.equals(d2)); // true
Метод учитывает:
const { LocalDate, LocalDateTime } = require('@js-joda/core');
const date = LocalDate.parse('2025-03-10');
const dateTime = LocalDateTime.parse('2025-03-10T00:00');
console.log(date.equals(dateTime)); // false
Даже если значения визуально совпадают, объекты разных типов равными не считаются.
Для проверки последовательности используются методы:
isBefore()isAfter()isEqual()const start = LocalDate.parse('2025-01-01');
const end = LocalDate.parse('2025-12-31');
console.log(start.isBefore(end)); // true
Метод возвращает:
true, если объект расположен раньше;false в остальных случаях.console.log(end.isAfter(start)); // true
const a = LocalDate.parse('2025-05-01');
const b = LocalDate.parse('2025-05-01');
console.log(a.isEqual(b)); // true
Для LocalDate результат обычно одинаков.
Однако при работе с часовыми поясами различия становятся критичными.
const {
ZonedDateTime,
ZoneId
} = require('@js-joda/core');
const moscow = ZonedDateTime.now(ZoneId.of('Europe/Moscow'));
const london = ZonedDateTime.now(ZoneId.of('Europe/London'));
equals() сравнивает:
console.log(moscow.equals(london));
Результат почти всегда будет false.
Метод isEqual() сравнивает реальные моменты времени.
const a = ZonedDateTime.parse(
'2025-05-01T12:00+03:00[Europe/Moscow]'
);
const b = ZonedDateTime.parse(
'2025-05-01T10:00+01:00[Europe/Paris]'
);
console.log(a.isEqual(b)); // true
Несмотря на разное локальное время, оба объекта указывают на один и тот же момент.
Метод compareTo() возвращает число:
| Значение | Смысл |
|---|---|
< 0 |
объект меньше |
0 |
объекты равны |
> 0 |
объект больше |
const d1 = LocalDate.parse('2025-01-01');
const d2 = LocalDate.parse('2025-06-01');
console.log(d1.compareTo(d2)); // отрицательное число
console.log(d2.compareTo(d1)); // положительное число
console.log(d1.compareTo(d1)); // 0
compareTo() особенно полезен при сортировке
массивов.
const dates = [
LocalDate.parse('2025-12-01'),
LocalDate.parse('2025-01-01'),
LocalDate.parse('2025-06-01')
];
dates.sort((a, b) => a.compareTo(b));
console.log(dates);
Тип LocalTime поддерживает те же методы.
const { LocalTime } = require('@js-joda/core');
const t1 = LocalTime.parse('09:30');
const t2 = LocalTime.parse('18:45');
console.log(t1.isBefore(t2)); // true
const { LocalDateTime } = require('@js-joda/core');
const a = LocalDateTime.parse('2025-05-10T12:00');
const b = LocalDateTime.parse('2025-05-10T14:00');
console.log(a.isBefore(b)); // true
Сравнение выполняется последовательно:
Тип Instant предназначен для точного сравнения моментов
времени.
const { Instant } = require('@js-joda/core');
const i1 = Instant.parse('2025-05-01T10:00:00Z');
const i2 = Instant.parse('2025-05-01T10:00:01Z');
console.log(i1.isBefore(i2)); // true
Instant не зависит:
Поэтому сравнение через Instant считается наиболее
безопасным для серверной логики.
const zoned = ZonedDateTime.parse(
'2025-05-01T12:00+03:00[Europe/Moscow]'
);
const instant = zoned.toInstant();
console.log(instant);
Частая задача — определить, попадает ли дата в диапазон.
function isBetween(date, start, end) {
return (
!date.isBefore(start) &&
!date.isAfter(end)
);
}
Использование:
const date = LocalDate.parse('2025-06-15');
const start = LocalDate.parse('2025-01-01');
const end = LocalDate.parse('2025-12-31');
console.log(isBetween(date, start, end));
function isStrictlyBetween(date, start, end) {
return (
date.isAfter(start) &&
date.isBefore(end)
);
}
function overlaps(start1, end1, start2, end2) {
return (
!end1.isBefore(start2) &&
!start1.isAfter(end2)
);
}
const s1 = LocalDate.parse('2025-01-01');
const e1 = LocalDate.parse('2025-03-01');
const s2 = LocalDate.parse('2025-02-01');
const e2 = LocalDate.parse('2025-04-01');
console.log(
overlaps(s1, e1, s2, e2)
); // true
Тип Duration представляет временной интервал.
const { Duration } = require('@js-joda/core');
const d1 = Duration.ofHours(5);
const d2 = Duration.ofMinutes(200);
console.log(d1.compareTo(d2));
Period работает с календарными единицами.
const { Period } = require('@js-joda/core');
const p1 = Period.ofDays(10);
const p2 = Period.ofWeeks(2);
console.log(p1.equals(p2)); // false
Period не нормализует значения автоматически.
Period.ofWeeks(1)
Period.ofDays(7)
Это разные объекты.
const period = Period.ofMonths(15);
console.log(period.normalized());
Результат:
P1Y3M
const today = LocalDate.now();
const future = LocalDate.parse('2026-01-01');
console.log(future.isAfter(today));
function isExpired(expirationDate) {
return expirationDate.isBefore(LocalDate.now());
}
const a = LocalDateTime.parse('2025-05-01T12:00');
const b = LocalDateTime.parse('2025-05-01T12:00');
Эти объекты не содержат информации о часовом поясе.
Для распределённых систем это опасно.
const utc = ZonedDateTime.parse(
'2025-05-01T09:00Z[UTC]'
);
const berlin = ZonedDateTime.parse(
'2025-05-01T11:00+02:00[Europe/Berlin]'
);
console.log(utc.isEqual(berlin)); // true
Js-joda поддерживает наносекундную точность.
const a = LocalTime.parse('10:00:00.000000001');
const b = LocalTime.parse('10:00:00.000000002');
console.log(a.isBefore(b)); // true
Иногда необходимо сравнить только календарную часть.
const a = LocalDateTime.parse('2025-05-01T10:00');
const b = LocalDateTime.parse('2025-05-01T22:00');
console.log(
a.toLocalDate().equals(
b.toLocalDate()
)
);
console.log(
a.toLocalTime().equals(
b.toLocalTime()
)
);
Модуль ChronoUnit позволяет вычислять разницу между
значениями.
const {
LocalDate,
ChronoUnit
} = require('@js-joda/core');
const start = LocalDate.parse('2025-01-01');
const end = LocalDate.parse('2025-01-15');
const days = ChronoUnit.DAYS.between(start, end);
console.log(days);
if (ChronoUnit.DAYS.between(a, b) > 30) {
console.log('Больше месяца');
}
function sameMonth(a, b) {
return (
a.year() === b.year() &&
a.monthValue() === b.monthValue()
);
}
function sameYear(a, b) {
return a.year() === b.year();
}
Js-joda хорошо работает с Map и Set.
const set = new Set();
const date = LocalDate.parse('2025-05-01');
set.add(date);
console.log(
set.has(LocalDate.parse('2025-05-01'))
);
В обычном Set сравнение объектов выполняется по
ссылке.
Поэтому пример выше вернёт:
false
const map = new Map();
const date = LocalDate.parse('2025-05-01');
map.set(date.toString(), 'Holiday');
console.log(
map.get('2025-05-01')
);
date1 == date2
Нельзя использовать для временных объектов.
date1 === date2
Сравниваются ссылки, а не значения.
'01.02.2025' > '31.01.2025'
Строковое сравнение может давать неверный результат.
const a = LocalDate.parse('2025-02-01');
const b = LocalDate.parse('2025-01-31');
console.log(a.isAfter(b));
Методы Js-joda:
const events = [
LocalDate.parse('2025-01-01'),
LocalDate.parse('2026-01-01'),
LocalDate.parse('2024-01-01')
];
const today = LocalDate.now();
const futureEvents = events.filter(
event => event.isAfter(today)
);
console.log(futureEvents);
const logs = [
Instant.parse('2025-01-01T10:00:00Z'),
Instant.parse('2025-01-01T09:00:00Z'),
Instant.parse('2025-01-01T11:00:00Z')
];
logs.sort((a, b) => a.compareTo(b));
function nearest(target, dates) {
return dates.reduce((closest, current) => {
const currentDiff = Math.abs(
ChronoUnit.DAYS.between(target, current)
);
const closestDiff = Math.abs(
ChronoUnit.DAYS.between(target, closest)
);
return currentDiff < closestDiff
? current
: closest;
});
}
Использовать:
Instant
или:
ZonedDateTime
Использовать:
LocalDate
Использовать:
LocalTime
Использовать:
Duration
или:
Period
в зависимости от задачи.
== и ===;isBefore, isAfter,
isEqual;Instant;compareTo для сортировки;ChronoUnit для вычисления разницы;