В js-joda модель сравнения построена вокруг строгих правил
неизменяемых (immutable) временных типов и явной семантики хронологии.
Каждый тип времени — Instant, LocalDate,
LocalDateTime, ZonedDateTime — имеет
собственную систему сравнения, и корректная сортировка требует понимания
их различий, а не только применения стандартных операторов
JavaScript.
Базовая идея заключается в том, что временные объекты не приводятся автоматически к единому формату. Вместо этого используется явное сравнение через методы:
compareToisBeforeisAfterisEqualВсе основные типы реализуют метод compareTo,
возвращающий:
import { LocalDate } from '@js-joda/core';
const d1 = LocalDate.parse('2024-01-01');
const d2 = LocalDate.parse('2024-01-10');
d1.compareTo(d2); // < 0
d2.compareTo(d1); // > 0
Семантика сравнения строго типизирована: сравнение возможно только
между объектами одного типа. Попытка сравнить LocalDate и
LocalDateTime приводит к ошибочной логике или исключению в
зависимости от контекста использования.
Эти методы обеспечивают более читаемую форму выражения порядка:
d1.isBefore(d2); // true
d2.isAfter(d1); // true
d1.isEqual(d2); // false
В отличие от compareTo, данные методы выражают намерение
без необходимости интерпретировать числовой результат.
LocalDate сравнивается исключительно по календарной
дате:
import { LocalDate } from '@js-joda/core';
const a = LocalDate.of(2024, 5, 10);
const b = LocalDate.of(2024, 5, 11);
a.compareTo(b);
Время суток и часовой пояс отсутствуют, поэтому сравнение детерминировано и не зависит от окружения.
LocalDateTime включает дату и время, но без часового
пояса:
import { LocalDateTime } from '@js-joda/core';
const a = LocalDateTime.parse('2024-05-10T10:00');
const b = LocalDateTime.parse('2024-05-10T12:00');
a.isBefore(b);
Сравнение выполняется лексикографически: сначала дата, затем время.
ZonedDateTime учитывает часовой пояс, что делает
сравнение абсолютным во времени.
import { ZonedDateTime } from '@js-joda/core';
const a = ZonedDateTime.parse('2024-05-10T10:00+03:00[Europe/Moscow]');
const b = ZonedDateTime.parse('2024-05-10T09:00+01:00[Europe/Paris]');
a.isEqual(b); // может быть true в абсолютном времени
В отличие от LocalDateTime, сравнение здесь основано на
точке на временной оси, а не на локальном представлении.
Instant представляет момент времени в UTC и является
наиболее однозначным типом для сравнения:
import { Instant } from '@js-joda/core';
const a = Instant.parse('2024-05-10T07:00:00Z');
const b = Instant.parse('2024-05-10T08:00:00Z');
a.isBefore(b);
Стандартный подход в JavaScript — использование
Array.prototype.sort, но с явным компаратором.
import { LocalDate } from '@js-joda/core';
const dates = [
LocalDate.parse('2024-01-05'),
LocalDate.parse('2024-01-01'),
LocalDate.parse('2024-01-03')
];
dates.sort((a, b) => a.compareTo(b));
Компаратор напрямую делегирует логику библиотеке, что исключает ошибки преобразования.
dates.sort((a, b) => b.compareTo(a));
или через инверсию:
dates.sort((a, b) => -a.compareTo(b));
При работе с датой и временем сортировка учитывает оба компонента:
import { LocalDateTime } from '@js-joda/core';
const items = [
LocalDateTime.parse('2024-05-10T09:00'),
LocalDateTime.parse('2024-05-10T08:30'),
LocalDateTime.parse('2024-05-09T23:00')
];
items.sort((a, b) => a.compareTo(b));
Лексикографический порядок гарантирует корректную сортировку без дополнительных преобразований.
При наличии временных зон сортировка становится глобальной:
import { ZonedDateTime } from '@js-joda/core';
const items = [
ZonedDateTime.parse('2024-05-10T10:00+03:00[Europe/Moscow]'),
ZonedDateTime.parse('2024-05-10T09:00+01:00[Europe/Paris]'),
ZonedDateTime.parse('2024-05-10T08:00Z')
];
items.sort((a, b) => a.compareTo(b));
Порядок определяется моментом времени на UTC-линии, а не локальными представлениями.
Часто требуется комбинировать несколько уровней сортировки, например дату и время создания события.
events.sort((a, b) => {
const dateCompare = a.date.compareTo(b.date);
if (dateCompare !== 0) return dateCompare;
return a.time.compareTo(b.time);
});
Такой подход обеспечивает стабильную сортировку при совпадении первичного ключа.
При необходимости унифицировать различные типы времени применяется
преобразование к Instant:
events.sort((a, b) =>
a.toInstant().compareTo(b.toInstant())
);
Это устраняет различия между зонами и локальными представлениями, приводя всё к единой временной оси.
Иногда сортировка строится не напрямую через сравнение, а через вычисление разницы:
import { ChronoUnit } from '@js-joda/core';
events.sort((a, b) =>
ChronoUnit.MINUTES.between(a, b)
);
Положительное значение указывает на порядок, отрицательное — на обратный, что эквивалентно компаратору.
Все типы в библиотеке являются immutable. Это означает, что:
sort работает только с ссылками
массиваconst original = [date1, date2];
const sorted = [...original].sort((a, b) => a.compareTo(b));
Копирование массива сохраняет исходный порядок данных, что критично для предсказуемости логики.
Встроенный Date в JavaScript использует числовое
представление времени, что позволяет сравнение через вычитание. В
отличие от этого подхода, js-joda требует явного вызова методов,
исключая неявные преобразования и ошибки, связанные с часовыми поясами и
локалями.
// JS Date
a - b;
// js-joda
a.compareTo(b);
Разделение типов и явные методы сравнения устраняют неоднозначность в интерпретации времени.
При использовании одного и того же компаратора результаты сортировки остаются стабильными независимо от окружения выполнения. Это достигается благодаря:
compareToТакая модель особенно важна при обработке временных рядов, журналов событий и расписаний, где порядок должен оставаться неизменным при переносе между системами.