Часовой пояс в JavaScript не является частью базового объекта
Date, поэтому любые операции, которые приводят к
преобразованию между Luxon и нативным Date, потенциально
ведут к его потере или неявному изменению интерпретации времени. В
библиотеке Luxon это одна из ключевых проблемных зон, поскольку модель
данных Luxon принципиально отличается от встроенной в язык.
Нативный объект Date хранит момент времени в виде
количества миллисекунд с эпохи Unix (UTC). Часовой пояс как сущность в
нём отсутствует. Любая информация о зоне существует только на уровне
отображения (локальная зона среды выполнения) и не сохраняется внутри
объекта.
Это приводит к фундаментальному эффекту:
Date хранит момент времениПри переходах между этими моделями происходит потеря части контекста.
В Luxon дата-время представлено объектом DateTime,
который включает:
Europe/Paris, Asia/Almaty,
UTC)Пример:
import { DateTime } from "luxon";
const dt = DateTime.now().setZone("Asia/Almaty");
Здесь сохраняется именно зона, а не только смещение.
Ключевая точка деградации происходит при вызове:
const jsDate = dt.toJSDate();
jsDate содержит только timestamp. Информация о
"Asia/Almaty" исчезает полностью.
При обратном преобразовании:
const dt2 = DateTime.fromJSDate(jsDate);
Luxon создаёт объект в локальной системной зоне окружения, а не восстанавливает исходную.
Это означает:
System ZoneОдин и тот же timestamp может быть интерпретирован по-разному:
const dt = DateTime.fromISO("2026-05-24T12:00:00", { zone: "Asia/Almaty" });
const jsDate = dt.toJSDate();
const dt2 = DateTime.fromJSDate(jsDate);
console.log(dt.zoneName); // Asia/Almaty
console.log(dt2.zoneName); // system zone
Несмотря на идентичный момент времени, контекст отображения утрачен.
Типичный сценарий потери зоны:
const payload = {
time: DateTime.now().setZone("Asia/Almaty")
};
const json = JSON.stringify(payload);
После этого:
const parsed = JSON.parse(json);
Получается строка без информации о зоне. Если далее восстановить:
DateTime.fromISO(parsed.time)
Luxon применит системную зону или UTC (в зависимости от формата строки), но исходная зона не восстановится.
ISO-строки могут содержать или не содержать зону:
DateTime.fromISO("2026-05-24T12:00:00+06:00");
или
DateTime.fromISO("2026-05-24T12:00:00Z");
В этих случаях Luxon восстанавливает момент времени, но не оригинальную IANA-зону, только фиксированное смещение.
DateTime.fromISO("2026-05-24T12:00:00");
Здесь используется локальная зона окружения, что часто приводит к смещению логики приложения при переносе между серверами.
Метод setZone управляет тем, как интерпретируется время
при смене зоны:
dt.setZone("UTC");
По умолчанию:
Но при:
dt.setZone("UTC", { keepLocalTime: true });
происходит обратное:
Это критическая точка, где может возникнуть иллюзия «потери времени» или «смещения на несколько часов».
Если зона не указана явно, Luxon использует системную:
DateTime.local();
или
DateTime.now();
В распределённых системах это создаёт проблему:
В результате один и тот же код даёт разные zoneName.
Наиболее частый паттерн деградации:
toJSDate()fromJSDate()В итоге:
Luxon не сохраняет IANA-зону в Date и требует явного
сериализационного слоя.
Практический подход:
const serialized = {
iso: dt.toISO(),
zone: dt.zoneName
};
Восстановление:
const restored = DateTime.fromISO(serialized.iso, {
zone: serialized.zone
});
Это единственный способ сохранить семантику времени полностью.
При операциях:
dt.plus({ hours: 5 });
зона сохраняется, но при преобразовании в JS Date или
строку без зоны возможна утрата контекста.
Особенно опасны цепочки:
DateTime.now()
.setZone("Asia/Almaty")
.toJSDate()
.toISOString();
На выходе остаётся только UTC-строка без информации о исходной зоне.
Проблема усиливается при переходе через летнее время:
Luxon корректно учитывает DST только пока сохраняется IANA-зона.
После преобразования в Date эта информация исчезает.
DateTime → Date → DateTimefromISO без указания зоныВо всех случаях итог одинаков: остаётся только абсолютное время без контекста его локального представления.
В архитектуре приложений с Luxon обычно выделяются уровни:
DateTime с зонойПотеря зоны считается допустимой только на транспортном или хранилищном уровне, но не в доменной модели.
Если зона не задана явно:
DateTime.fromMillis(0);
или
DateTime.local();
используется системная зона окружения, что делает поведение зависимым от:
Это приводит к непредсказуемым расхождениям при переносе данных между средами.