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

В Luxon объект DateTime представляет момент времени с учётом таймзоны, календарных преобразований и точности до миллисекунд. В отличие от «сырых» чисел или строк, сравнение таких объектов требует приведения к единой временной шкале.

Ключевая особенность: любое сравнение сводится к абсолютному времени в UTC, выраженному в миллисекундах с Unix-эпохи.

Это означает, что логика упорядочивания базируется не на строковом представлении и не на локальном формате, а на числовом значении временной точки.


Числовое представление и приведение типов

Каждый экземпляр DateTime в Luxon имеет внутреннюю временную метку, доступную через миллисекунды.

Основные способы получения числового представления:

  • toMillis()
  • valueOf()
  • неявное приведение к числу
import { DateTime } from "luxon";

const dt = DateTime.now();

dt.toMillis();   // явное получение timestamp
dt.valueOf();    // аналогично
+dt;             // неявное приведение

valueOf() переопределён таким образом, чтобы объект корректно участвовал в числовых операциях JavaScript. Это позволяет использовать стандартные операторы сравнения без дополнительных преобразований.


Операторы сравнения в JavaScript

Так как DateTime приводит себя к числу, стандартные операторы работают напрямую:

const a = DateTime.fromISO("2024-01-01T10:00:00");
const b = DateTime.fromISO("2024-01-01T12:00:00");

a < b;   // true
a > b;   // false
a <= b;  // true

Механизм основан на следующем шаге:

  1. Объекты преобразуются через valueOf()
  2. Получаются миллисекунды
  3. Выполняется числовое сравнение

Таким образом, Luxon интегрируется в стандартную модель сравнения JavaScript без дополнительных функций.


Метод equals и строгое равенство

Оператор === не подходит для сравнения экземпляров DateTime, поскольку сравнивает ссылки на объекты, а не их временное значение.

Для корректного сравнения используется метод:

a.equals(b);

Он проверяет:

  • одинаковый момент времени
  • одинаковую таймзону (или эквивалентное представление)
  • совпадение всех значимых компонентов

Пример:

const a = DateTime.fromISO("2024-01-01T00:00:00+01:00");
const b = DateTime.fromISO("2023-12-31T23:00:00Z");

a.equals(b); // true

Оба объекта представляют один и тот же момент времени, несмотря на разный формат входных данных.


Таймзоны и влияние на сравнение

Сравнение всегда происходит через абсолютное время, но отображение и создание объектов может вводить различия.

const a = DateTime.fromISO("2024-01-01T10:00", { zone: "Europe/Berlin" });
const b = DateTime.fromISO("2024-01-01T09:00", { zone: "UTC" });

a > b; // зависит от реального смещения, но сравнение идёт по UTC

Важно учитывать:

  • разные таймзоны не влияют на итоговое сравнение
  • влияет только момент времени в UTC

Метод hasSame: сравнение по точности

Часто требуется сравнивать не абсолютное значение, а совпадение по единице измерения (год, месяц, день и т.д.).

Для этого используется:

a.hasSame(b, "day");

Возможные единицы:

  • year
  • month
  • day
  • hour
  • minute
  • second

Пример:

const a = DateTime.fromISO("2024-01-01T10:00");
const b = DateTime.fromISO("2024-01-01T23:00");

a.hasSame(b, "day"); // true
a.hasSame(b, "hour"); // false

Метод игнорирует более мелкие компоненты времени, фокусируясь на заданной точности.


Границы периода: startOf и endOf

Для сравнения диапазонов часто используется нормализация времени к границам единицы измерения.

const start = dt.startOf("day");
const end = dt.endOf("day");

Это позволяет строить логические проверки:

const target = DateTime.now();

target >= start && target <= end;

Такой подход особенно полезен при работе с фильтрацией событий, группировкой и временными окнами.


Сравнение диапазонов через Interval

Хотя DateTime отвечает за момент времени, Luxon также предоставляет Interval для работы с промежутками.

Основные операции:

  • пересечение
  • включение
  • соприкосновение
import { DateTime, Interval } from "luxon";

const i1 = Interval.fromDateTimes(
  DateTime.fromISO("2024-01-01"),
  DateTime.fromISO("2024-01-10")
);

const i2 = Interval.fromDateTimes(
  DateTime.fromISO("2024-01-05"),
  DateTime.fromISO("2024-01-15")
);

i1.overlaps(i2);

Хотя это не прямые операторы сравнения, они расширяют семантику временных отношений.


Сортировка и сравнение коллекций

Благодаря числовому представлению DateTime, сортировка выполняется стандартным образом:

const list = [
  DateTime.fromISO("2024-01-03"),
  DateTime.fromISO("2024-01-01"),
  DateTime.fromISO("2024-01-02")
];

list.sort((a, b) => a - b);

Или явно:

list.sort((a, b) => a.toMillis() - b.toMillis());

Оба варианта эквивалентны, так как valueOf() возвращает миллисекунды.


Особенности и типовые ошибки

Неявное сравнение объектов

a == b;
a === b;

Оба варианта сравнивают ссылки, а не временные значения.


Некорректные DateTime

Если объект невалиден:

const dt = DateTime.invalid("error");

Любые операции сравнения могут давать неожиданные результаты, поэтому проверка:

dt.isValid

является обязательной перед сравнением.


Потеря точности при приведении

Хотя Luxon работает в миллисекундах, внешние источники могут давать менее точные данные (например, секунды). При смешении уровней точности возможно ложное неравенство при строгом сравнении.


Разные уровни абстракции

Сравнение может происходить на трёх уровнях:

  • момент времени (<, >)
  • равенство момента (equals)
  • равенство по единице (hasSame)

Неверный выбор уровня приводит к логическим ошибкам в бизнес-логике.


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

  • Упорядочивание событий → числовые операторы или toMillis()
  • Проверка идентичного момента → equals
  • Проверка календарного совпадения → hasSame
  • Работа с временными окнами → startOf / endOf
  • Работа с диапазонами → Interval