В библиотеке Luxon работа с разницей между датами строится на двух
ключевых сущностях: Duration и
Interval. Первая используется для представления
продолжительности, вторая — для описания промежутка между двумя
моментами времени как диапазона. Основной инструмент вычисления разницы
— метод diff, возвращающий объект Duration, который
позволяет оперировать разницей в различных единицах измерения.
DateTime.diffМетод diff применяется к объекту DateTime и
принимает другой момент времени в качестве аргумента. Результатом
является объект Duration.
import { DateTime } from "luxon";
const start = DateTime.fromISO("2024-01-01T00:00:00");
const end = DateTime.fromISO("2024-01-10T12:00:00");
const diff = end.diff(start);
По умолчанию результат выражается в миллисекундах, если не указаны единицы измерения.
diff.toObject();
// { milliseconds: 820800000 }
Одной из ключевых особенностей Luxon является возможность явно задавать единицы измерения результата.
const diffDays = end.diff(start, "days");
diffDays.toObject();
// { days: 9.5 }
Поддерживаются следующие базовые единицы:
Можно одновременно получать несколько единиц:
const diffComplex = end.diff(start, ["days", "hours", "minutes"]);
diffComplex.toObject();
// {
// days: 9,
// hours: 12,
// minutes: 0
// }
В этом случае Luxon выполняет разложение разницы по указанным компонентам.
Duration в Luxon хранит дробные значения, но может быть приведён к целым значениям с помощью методов округления.
const diff = end.diff(start, "days");
diff.as("days"); // 9.5
diff.toObject(); // { days: 9.5 }
Для округления используются методы:
shiftTo() — перераспределение единицnormalize() — нормализация значенийtoFormat() — форматированное представлениеПример нормализации:
const d = end.diff(start, ["days", "hours"]).normalize();
diffNowМетод diffNow вычисляет разницу между указанной датой и
текущим моментом времени.
const future = DateTime.fromISO("2025-01-01");
const diff = future.diffNow("days");
Если дата находится в будущем, результат будет положительным. Если в прошлом — отрицательным.
const past = DateTime.fromISO("2020-01-01");
past.diffNow("days").toObject();
// отрицательное значение
Luxon не ограничивает разницу по знаку. Направление вычисления зависит от порядка аргументов:
end.diff(start); // положительное значение
start.diff(end); // отрицательное значение
Это важно при построении логики временных интервалов, где направление имеет смысл (например, обратный отсчёт).
as()Объект Duration позволяет получить числовое значение в конкретной единице без изменения структуры:
const diff = end.diff(start);
diff.as("hours"); // 228
diff.as("days"); // 9.5
Метод as полезен для расчётов, где требуется одно
числовое значение.
При работе с несколькими единицами возникает ситуация, когда значения выходят за логические пределы (например, 90 минут). Luxon предоставляет механизм нормализации:
const d = end.diff(start, ["hours", "minutes"]).normalize();
После нормализации результат приводится к корректному распределению единиц:
Хотя diff возвращает Duration, для анализа временного
промежутка как диапазона используется Interval.
import { Interval } from "luxon";
const interval = Interval.fromDateTimes(start, end);
Interval предоставляет дополнительные возможности:
interval.length("days");
Interval позволяет определять пересечения временных промежутков:
const a = Interval.fromDateTimes(
DateTime.fromISO("2024-01-01"),
DateTime.fromISO("2024-01-10")
);
const b = Interval.fromDateTimes(
DateTime.fromISO("2024-01-05"),
DateTime.fromISO("2024-01-15")
);
a.overlaps(b); // true
Interval позволяет более естественно работать с диапазонами времени:
const duration = interval.toDuration("days");
duration.toObject(); // { days: 9 }
В отличие от diff, Interval ориентирован на работу с
диапазоном как с сущностью, а не просто разницей двух точек.
Особенность Luxon заключается в различии между:
Календарные единицы зависят от календарной системы и длины месяцев.
const a = DateTime.fromISO("2024-01-01");
const b = DateTime.fromISO("2025-01-01");
b.diff(a, "months").toObject();
// { months: 12 }
Но при более сложных интервалах возможны дробные значения:
const a = DateTime.fromISO("2024-01-31");
const b = DateTime.fromISO("2024-02-29");
b.diff(a, "months").toObject();
// значение может быть дробным
DateTime в Luxon всегда учитывает временную зону. Разница между датами может изменяться при переходе между зонами.
const a = DateTime.fromISO("2024-01-01T10:00", { zone: "UTC" });
const b = DateTime.fromISO("2024-01-01T10:00", { zone: "Europe/Berlin" });
b.diff(a, "hours").toObject();
Такой расчёт учитывает смещение UTC и может давать неожиданные результаты при игнорировании зоны.
const diff = end.diff(start, ["years", "months", "days", "hours"]);
Используется для отображения человеко-читаемых интервалов:
Часто применяется комбинация:
const duration = end.diff(start).shiftTo("days", "hours", "minutes");
ShiftTo позволяет перераспределить миллисекундное значение в удобные компоненты.
Luxon опирается на миллисекундную точность. При работе с большими диапазонами возможны:
const event = DateTime.fromISO("2026-12-31");
const daysLeft = event.diffNow("days").toObject();
const birth = DateTime.fromISO("1990-05-10");
const age = DateTime.now().diff(birth, "years").toObject();
const start = DateTime.now();
// выполнение операции
const end = DateTime.now();
const duration = end.diff(start, "milliseconds");
Внутренняя модель Luxon строится на трёх уровнях:
Метод diff формирует Duration, который может быть
преобразован, нормализован и представлен в различных единицах,
обеспечивая гибкость при работе с временными вычислениями различной
сложности.