Сравнение и абсолютные значения

Библиотека js-joda предоставляет строгую модель работы с датой и временем, основанную на API Java java.time. Одной из ключевых возможностей библиотеки является корректное сравнение временных объектов: дат, времени, дат со временем, периодов и длительностей.

В отличие от стандартного объекта Date, сравнение в Js-joda построено на неизменяемых типах и предсказуемых правилах.


Основные методы сравнения

Практически все временные типы поддерживают методы:

  • equals()
  • isBefore()
  • isAfter()
  • compareTo()

Наиболее часто используются:

const { LocalDate } = require('@js-joda/core');

const first = LocalDate.parse('2025-03-10');
const second = LocalDate.parse('2025-03-15');

console.log(first.isBefore(second)); // true
console.log(first.isAfter(second));  // false
console.log(first.equals(second));   // false

Метод equals()

Метод equals() проверяет полное равенство объектов.

const { LocalDate } = require('@js-joda/core');

const a = LocalDate.of(2025, 5, 1);
const b = LocalDate.of(2025, 5, 1);

console.log(a.equals(b)); // true

Важно понимать: сравнивается именно значение даты, а не ссылка на объект.

Отличие от оператора ===

console.log(a === b); // false

Оператор === сравнивает ссылки в памяти, а equals() — содержимое объектов.


Метод isBefore()

Метод isBefore() проверяет, находится ли текущий объект раньше другого.

const start = LocalDate.parse('2025-01-01');
const end = LocalDate.parse('2025-12-31');

console.log(start.isBefore(end)); // true

Сравнение времени

const { LocalTime } = require('@js-joda/core');

const morning = LocalTime.parse('09:00');
const evening = LocalTime.parse('18:00');

console.log(morning.isBefore(evening)); // true

Метод isAfter()

Метод работает противоположным образом.

const later = LocalDate.parse('2025-08-01');
const earlier = LocalDate.parse('2025-02-01');

console.log(later.isAfter(earlier)); // true

Метод compareTo()

compareTo() возвращает числовой результат:

  • отрицательное число — объект меньше
  • 0 — объекты равны
  • положительное число — объект больше
const d1 = LocalDate.parse('2025-04-01');
const d2 = LocalDate.parse('2025-04-10');

console.log(d1.compareTo(d2)); // -9
console.log(d2.compareTo(d1)); // 9

Практическое применение

Метод особенно полезен при сортировке.

const dates = [
    LocalDate.parse('2025-06-10'),
    LocalDate.parse('2025-01-01'),
    LocalDate.parse('2025-03-15')
];

dates.sort((a, b) => a.compareTo(b));

console.log(dates);

Сравнение LocalDateTime

Тип LocalDateTime сравнивает одновременно и дату, и время.

const { LocalDateTime } = require('@js-joda/core');

const first = LocalDateTime.parse('2025-05-01T10:00');
const second = LocalDateTime.parse('2025-05-01T12:00');

console.log(first.isBefore(second)); // true

Последовательность сравнения

Сначала сравнивается:

  1. год
  2. месяц
  3. день
  4. часы
  5. минуты
  6. секунды
  7. наносекунды

Сравнение ZonedDateTime

Тип ZonedDateTime учитывает временную зону.

const { ZonedDateTime, ZoneId } = require('@js-joda/core');

const moscow = ZonedDateTime.now(ZoneId.of('Europe/Moscow'));
const tokyo = ZonedDateTime.now(ZoneId.of('Asia/Tokyo'));

console.log(moscow.isBefore(tokyo));

Особенность сравнения

Сравнение происходит по глобальному времени UTC, а не по локальному отображению.

Например:

const a = ZonedDateTime.parse('2025-05-01T10:00+03:00[Europe/Moscow]');
const b = ZonedDateTime.parse('2025-05-01T09:00+02:00[Europe/Berlin]');

console.log(a.equals(b)); // true

Обе даты представляют один и тот же момент времени.


Сравнение Instant

Тип Instant предназначен для абсолютного времени.

const { Instant } = require('@js-joda/core');

const i1 = Instant.parse('2025-05-01T10:00:00Z');
const i2 = Instant.parse('2025-05-01T11:00:00Z');

console.log(i1.isBefore(i2)); // true

Instant особенно удобен:

  • для серверного времени
  • логирования
  • таймеров
  • синхронизации событий
  • работы с API

Абсолютные значения Duration

Тип Duration хранит длительность во времени.

const { Duration } = require('@js-joda/core');

const duration = Duration.ofHours(-5);

console.log(duration.toHours()); // -5

Метод abs()

Для получения абсолютного значения используется abs().

const positive = duration.abs();

console.log(positive.toHours()); // 5

Абсолютные значения Period

Period работает с календарными единицами:

  • годы
  • месяцы
  • дни
const { Period } = require('@js-joda/core');

const period = Period.of(0, -3, -10);

console.log(period.months()); // -3
console.log(period.days());   // -10

Преобразование в абсолютное значение

const absolute = period.abs();

console.log(absolute.months()); // 3
console.log(absolute.days());   // 10

Проверка диапазонов дат

Очень распространённая задача — определить, находится ли дата внутри диапазона.

const current = LocalDate.parse('2025-06-15');

const start = LocalDate.parse('2025-06-01');
const end = LocalDate.parse('2025-06-30');

const inside =
    !current.isBefore(start) &&
    !current.isAfter(end);

console.log(inside); // true

Исключение границ диапазона

Иногда требуется строгая проверка без включения границ.

const inside =
    current.isAfter(start) &&
    current.isBefore(end);

Сравнение с текущей датой

const today = LocalDate.now();
const target = LocalDate.parse('2025-12-31');

if (target.isAfter(today)) {
    console.log('Дата ещё не наступила');
}

Определение просроченных значений

const expiration = LocalDate.parse('2025-01-01');

if (LocalDate.now().isAfter(expiration)) {
    console.log('Срок истёк');
}

Нахождение минимальной даты

const dates = [
    LocalDate.parse('2025-07-01'),
    LocalDate.parse('2025-01-15'),
    LocalDate.parse('2025-11-20')
];

const min = dates.reduce((a, b) =>
    a.isBefore(b) ? a : b
);

console.log(min.toString());

Нахождение максимальной даты

const max = dates.reduce((a, b) =>
    a.isAfter(b) ? a : b
);

Сортировка объектов по времени

const events = [
    {
        title: 'Meeting',
        date: LocalDate.parse('2025-06-10')
    },
    {
        title: 'Conference',
        date: LocalDate.parse('2025-01-20')
    },
    {
        title: 'Release',
        date: LocalDate.parse('2025-04-15')
    }
];

events.sort((a, b) =>
    a.date.compareTo(b.date)
);

console.log(events);

Сравнение Duration

const d1 = Duration.ofMinutes(30);
const d2 = Duration.ofHours(1);

console.log(d1.compareTo(d2)); // отрицательное число

Проверка равенства длительности

const a = Duration.ofSeconds(60);
const b = Duration.ofMinutes(1);

console.log(a.equals(b)); // true

Сравнение Period

Period сравнивать сложнее, поскольку месяцы имеют разную длину.

const p1 = Period.ofMonths(1);
const p2 = Period.ofDays(30);

Такие значения нельзя считать эквивалентными автоматически.

Поэтому Period не предназначен для прямого сравнения продолжительности времени.


Ошибки при сравнении разных типов

Js-joda строго разделяет типы.

Например:

const date = LocalDate.now();
const time = LocalTime.now();

date.equals(time);

Такой код всегда вернёт false, поскольку объекты относятся к разным типам.


Сравнение через epoch day

LocalDate можно преобразовать в количество дней от эпохи Unix.

const date = LocalDate.parse('2025-05-10');

console.log(date.toEpochDay());

Это полезно:

  • для математических вычислений
  • хранения чисел в БД
  • оптимизации сортировки

Пример

const a = LocalDate.parse('2025-01-01').toEpochDay();
const b = LocalDate.parse('2025-12-31').toEpochDay();

console.log(a < b); // true

Сравнение через epoch second

Для Instant существует метод:

instant.epochSecond()

Пример:

const first = Instant.parse('2025-05-01T00:00:00Z');
const second = Instant.parse('2025-05-02T00:00:00Z');

console.log(
    first.epochSecond() <
    second.epochSecond()
);

Работа с отрицательными Duration

const duration = Duration.between(
    LocalTime.parse('18:00'),
    LocalTime.parse('10:00')
);

console.log(duration.toHours()); // -8

Получение абсолютного значения

console.log(duration.abs().toHours()); // 8

Проверка равенства моментов времени в разных зонах

const moscow = ZonedDateTime.parse(
    '2025-05-01T15:00+03:00[Europe/Moscow]'
);

const london = ZonedDateTime.parse(
    '2025-05-01T13:00+01:00[Europe/London]'
);

console.log(moscow.equals(london)); // true

Проверка совпадения только даты

Иногда важно игнорировать время.

const first = LocalDateTime.parse(
    '2025-05-01T10:00'
);

const second = LocalDateTime.parse(
    '2025-05-01T22:00'
);

console.log(
    first.toLocalDate()
        .equals(second.toLocalDate())
);

Проверка совпадения только времени

console.log(
    first.toLocalTime()
        .equals(second.toLocalTime())
);

Иммутабельность при сравнении

Все объекты Js-joda неизменяемы.

const date = LocalDate.now();

const updated = date.plusDays(5);

console.log(date);
console.log(updated);

Сравнения никогда не изменяют исходные значения.


Производительность compareTo()

compareTo() реализован максимально эффективно:

  • сравнение происходит по внутренним числовым значениям
  • отсутствуют мутации объектов
  • не создаются промежуточные структуры

Поэтому сортировка больших массивов работает значительно стабильнее по сравнению со строковым сравнением дат.


Практический пример проверки интервала

function isActive(start, end) {
    const now = LocalDate.now();

    return !now.isBefore(start) &&
           !now.isAfter(end);
}

const active = isActive(
    LocalDate.parse('2025-01-01'),
    LocalDate.parse('2025-12-31')
);

console.log(active);

Практический пример вычисления абсолютной разницы

const { ChronoUnit } = require('@js-joda/core');

const first = LocalDate.parse('2025-01-01');
const second = LocalDate.parse('2025-01-20');

const diff = Math.abs(
    ChronoUnit.DAYS.between(first, second)
);

console.log(diff); // 19

Сравнение дат в условиях

if (date.isBefore(limit)) {
    console.log('Меньше');
} else if (date.isAfter(limit)) {
    console.log('Больше');
} else {
    console.log('Равны');
}

Проверка будущих и прошедших дат

const target = LocalDate.parse('2030-01-01');

const isFuture = target.isAfter(LocalDate.now());
const isPast = target.isBefore(LocalDate.now());

console.log(isFuture);
console.log(isPast);

Сравнение наносекунд

Js-joda поддерживает точность до наносекунд.

const first = LocalTime.parse('10:00:00.000000001');
const second = LocalTime.parse('10:00:00.000000002');

console.log(first.isBefore(second)); // true

Это особенно важно:

  • в финансовых системах
  • высоконагруженных API
  • системах мониторинга
  • обработке событий в реальном времени