При работе с часовыми поясами существует два принципиально разных сценария:
Luxon позволяет явно управлять обоими вариантами через метод
setZone().
Абсолютный момент времени — это конкретная точка на временной шкале UTC. Например:
2025-03-10T12:00:00ZЕсли объект времени переводится в другую временную зону с сохранением момента времени, изменяется только представление даты и времени, но не сама точка времени.
Пример:
import { DateTime } from 'luxon'
const dt = DateTime.fromISO(
'2025-03-10T15:00:00',
{ zone: 'UTC' }
)
const moscow = dt.setZone('Europe/Moscow')
console.log(dt.toISO())
// 2025-03-10T15:00:00.000Z
console.log(moscow.toISO())
// 2025-03-10T18:00:00.000+03:00
В этом примере:
15:00 UTC18:00 Europe/Moscow— это один и тот же момент времени.
setZone()
по умолчаниюМетод setZone() сохраняет момент времени
автоматически.
const dt = DateTime.now()
const tokyo = dt.setZone('Asia/Tokyo')
Luxon:
Это особенно важно при:
Timestamp остаётся одинаковым независимо от зоны.
const utc = DateTime.fromISO(
'2025-05-01T12:00:00',
{ zone: 'UTC' }
)
const berlin = utc.setZone('Europe/Berlin')
console.log(utc.toMillis())
console.log(berlin.toMillis())
Результат:
1746100800000
1746100800000
Миллисекунды совпадают полностью.
При смене зоны локальное время изменяется автоматически.
const dt = DateTime.fromISO(
'2025-06-01T10:00:00',
{ zone: 'UTC' }
)
console.log(dt.toString())
// 2025-06-01T10:00:00.000Z
console.log(
dt.setZone('America/New_York').toString()
)
// 2025-06-01T06:00:00.000-04:00
console.log(
dt.setZone('Asia/Tokyo').toString()
)
// 2025-06-01T19:00:00.000+09:00
Изменяются:
Но момент времени остаётся прежним.
Событие должно происходить одновременно для всех пользователей мира.
Примеры:
const release = DateTime.fromISO(
'2025-07-01T15:00:00Z'
)
const paris = release.setZone('Europe/Paris')
const seoul = release.setZone('Asia/Seoul')
Все пользователи увидят локальное представление одного события.
Логи всегда должны ссылаться на точный момент времени.
const logTime = DateTime.utc()
const localView = logTime.setZone(
'America/Los_Angeles'
)
Смена зоны нужна только для отображения.
Обычно время хранится:
При получении данных зона меняется только для интерфейса.
const dbDate = DateTime.fromISO(
'2025-04-01T08:00:00Z'
)
const userDate = dbDate.setZone(
'Asia/Almaty'
)
keepLocalTimeПо умолчанию Luxon сохраняет момент времени.
Однако иногда требуется сохранить локальные часы, а не timestamp.
Для этого используется:
keepLocalTime: true
Пример:
const dt = DateTime.fromObject(
{
year: 2025,
month: 5,
day: 1,
hour: 10
},
{ zone: 'UTC' }
)
const changed = dt.setZone(
'Europe/Berlin',
{ keepLocalTime: true }
)
console.log(dt.toISO())
// 2025-05-01T10:00:00.000Z
console.log(changed.toISO())
// 2025-05-01T10:00:00.000+02:00
Теперь:
10:00;dt.setZone('Asia/Tokyo')
Меняется:
Не меняется:
dt.setZone(
'Asia/Tokyo',
{ keepLocalTime: true }
)
Меняется:
Не меняется:
Исходное время:
const dt = DateTime.fromISO(
'2025-01-01T12:00:00',
{ zone: 'UTC' }
)
const result = dt.setZone('Asia/Tokyo')
console.log(result.toISO())
// 2025-01-01T21:00:00.000+09:00
Timestamp одинаковый.
const result = dt.setZone(
'Asia/Tokyo',
{ keepLocalTime: true }
)
console.log(result.toISO())
// 2025-01-01T12:00:00.000+09:00
Теперь это уже другой момент времени.
Частая проблема — перенос локального времени вместо абсолютного момента.
Неправильно:
const meeting = DateTime.fromISO(
'2025-08-01T09:00:00',
{ zone: 'Europe/Berlin' }
)
const ny = meeting.setZone(
'America/New_York',
{ keepLocalTime: true }
)
В результате создаётся другое событие.
Если международная конференция начинается:
2025-09-01 12:00 UTC
то нельзя сохранять локальные часы при переводе зоны.
Иначе пользователи увидят разные реальные моменты запуска.
Наиболее безопасная практика:
const utcTime = DateTime.utc()
const local = utcTime.setZone(
'Asia/Dubai'
)
toUTC()Метод toUTC() — специализированный вариант
setZone().
const local = DateTime.now()
const utc = local.toUTC()
Luxon:
toLocal()Метод toLocal() переводит объект в системную зону.
const utc = DateTime.utc()
const local = utc.toLocal()
Timestamp также сохраняется.
Luxon автоматически учитывает DST.
const dt = DateTime.fromISO(
'2025-03-30T01:30:00',
{ zone: 'UTC' }
)
const berlin = dt.setZone('Europe/Berlin')
console.log(berlin.toString())
Смещение может изменяться автоматически:
+01:00+02:00в зависимости от даты.
Иногда при переводе зоны меняется календарный день.
const utc = DateTime.fromISO(
'2025-01-01T23:30:00',
{ zone: 'UTC' }
)
const tokyo = utc.setZone('Asia/Tokyo')
console.log(tokyo.toISO())
// 2025-01-02T08:30:00.000+09:00
Дата изменилась:
1 января;2 января.Но момент времени остался тем же.
Для проверки можно использовать:
toMillis()
или:
valueOf()
Пример:
const a = DateTime.utc()
const b = a.setZone('Asia/Tokyo')
console.log(a.valueOf() === b.valueOf())
// true
Иногда перевод зоны не нужен.
const dt = DateTime.fromObject(
{
year: 2025,
month: 10,
day: 5,
hour: 14
},
{
zone: 'Europe/London'
}
)
В этом случае объект сразу создаётся в нужной зоне.
ISO-строка содержит информацию о смещении.
const dt = DateTime.now()
console.log(dt.toISO())
Пример:
2025-05-01T14:30:00.000+03:00
При восстановлении Luxon корректно восстанавливает момент времени.
const restored = DateTime.fromISO(isoString)
setZone() в цепочкахconst formatted = DateTime
.utc()
.setZone('Asia/Singapore')
.toFormat('dd.MM.yyyy HH:mm')
Luxon сохраняет timestamp на всех этапах, пока не используется
keepLocalTime.
Luxon хранит:
При обычном setZone():
timestamp остаётся прежним;
пересчитываются:
При keepLocalTime: true:
Объект Date всегда хранит UTC timestamp, но:
Luxon предоставляет:
Пример:
const native = new Date()
const luxon = DateTime.fromJSDate(native)
Использовать UTC:
DateTime.utc()
Преобразовывать время под пользователя:
serverDate.setZone(userZone)
Хранить:
Если событие должно всегда происходить в локальное время пользователя, использовать:
keepLocalTime: true
Например:
keepLocalTime без необходимостиЭто приводит к смещению реального времени события.
Опасный вариант:
2025-05-01 12:00
Без зоны невозможно определить абсолютный момент времени.
Неправильно:
DateTime.now()
DateTime.utc()
без понимания различий между ними.
setZone() по умолчаниюСохраняет:
Меняет:
keepLocalTime: trueСохраняет:
Меняет:
Для большинства приложений:
keepLocalTime без реальной необходимости.