Фиксированные смещения

Временная зона с фиксированным смещением представляет собой способ интерпретации даты и времени без учёта правил перехода на летнее и зимнее время. В основе лежит постоянная величина смещения относительно UTC, выраженная в минутах или часах. В Luxon такие зоны используются как упрощённая модель временной локализации, где календарные изменения региона игнорируются, а сохраняется только арифметическое смещение.

Сущность фиксированного смещения

Фиксированное смещение — это временная зона, в которой разница с UTC всегда постоянна.

Пример:

  • UTC+2 всегда означает +2 часа к UTC
  • UTC-5 всегда означает −5 часов
  • UTC+05:30 всегда означает +5 часов 30 минут

В отличие от IANA-зон (например, Europe/Berlin или America/New_York), фиксированное смещение:

  • не учитывает летнее время
  • не изменяется в течение года
  • не зависит от географических правил

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


Представление зон с фиксированным смещением в Luxon

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

Строковое указание зоны

Наиболее распространённый способ — строка в формате UTC-offset:

DateTime.fromObject(
  { year: 2026, month: 1, day: 1, hour: 12 },
  { zone: 'UTC+2' }
);

или:

DateTime.fromObject(
  { year: 2026, month: 1, day: 1, hour: 12 },
  { zone: 'UTC-05:00' }
);

Luxon интерпретирует такие значения как фиксированные смещения, не привязанные к правилам региона.


ISO 8601 с явным смещением

При разборе строк ISO 8601 смещение уже встроено в данные:

DateTime.fromISO('2026-01-01T10:00:00+03:00');

Такое значение автоматически превращается в дату с фиксированным смещением +180 минут.

Смещение становится частью временной точки, а не внешней настройкой.


Создание через объект зоны

Luxon предоставляет низкоуровневый механизм через FixedOffsetZone:

import { FixedOffsetZone } from 'luxon';

const zone = FixedOffsetZone.instance(180);

Здесь значение 180 означает количество минут смещения относительно UTC.

Использование:

DateTime.fromObject(
  { year: 2026, month: 1, day: 1, hour: 12 },
  { zone }
);

Поведение DateTime при фиксированных смещениях

При использовании фиксированной зоны Luxon вычисляет локальное время следующим образом:

  • базовая точка отсчёта остаётся UTC
  • к UTC применяется постоянное смещение
  • календарные правила региона не учитываются

Пример:

const dt = DateTime.fromISO('2026-01-01T10:00:00+02:00');

dt.zoneName; // 'UTC+2' (логически фиксированная зона)
dt.offset;   // 120 (минуты)

Свойство offset всегда отражает постоянное значение в минутах.


Отличие от IANA-зон

Ключевое различие проявляется при переходе на летнее время.

IANA-зона

DateTime.fromObject(
  { year: 2026, month: 6, day: 1, hour: 12 },
  { zone: 'Europe/Berlin' }
);
  • летом смещение может быть UTC+2
  • зимой смещение может быть UTC+1
  • значение зависит от даты

Фиксированное смещение

DateTime.fromObject(
  { year: 2026, month: 6, day: 1, hour: 12 },
  { zone: 'UTC+1' }
);
  • всегда UTC+1
  • сезонные изменения игнорируются
  • календарная логика региона отсутствует

Преобразование между зонами

Фиксированное смещение часто используется как промежуточное представление при конвертации времени.

const dt = DateTime.fromObject(
  { year: 2026, month: 1, day: 1, hour: 12 },
  { zone: 'UTC+3' }
);

const utc = dt.toUTC();
const local = dt.toLocal();

При этом:

  • toUTC() убирает смещение
  • toLocal() применяет системную локальную зону устройства

Поведение при смене зоны

Метод setZone сохраняет момент времени и изменяет только интерпретацию:

const dt = DateTime.fromISO('2026-01-01T10:00:00+03:00');

const shifted = dt.setZone('UTC-5');

Здесь происходит:

  • сохранение абсолютного момента времени
  • пересчёт отображаемого локального времени
  • применение нового фиксированного смещения

Потеря и сохранение локального времени

Важный аспект фиксированных смещений — контроль интерпретации исходных компонентов даты.

const dt = DateTime.fromObject(
  { year: 2026, month: 1, day: 1, hour: 10 },
  { zone: 'UTC+2', keepLocalTime: true }
);

При keepLocalTime: true:

  • заданные компоненты воспринимаются как «локальные»
  • смещение применяется без пересчёта исходного времени
  • возможно изменение абсолютного момента

Без этого параметра Luxon интерпретирует объект как момент времени в указанной зоне.


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

Фиксированное смещение всегда выражается в минутах:

const dt = DateTime.fromISO('2026-01-01T10:00:00+03:30');

dt.offset; // 210

Это значение:

  • положительное для восточных зон
  • отрицательное для западных
  • неизменно для конкретного DateTime

Нормализация времени

Luxon всегда хранит внутреннее значение как UTC-момент, а смещение применяется только при отображении:

  • вход: локальное время + смещение
  • хранение: UTC timestamp
  • вывод: локальное время в заданной зоне

Фиксированная зона влияет только на последний этап.


Типичные сценарии использования

Фиксированные смещения применяются в случаях, когда:

  • данные приходят с уже известным оффсетом (логирование, API)
  • требуется игнорировать DST
  • необходима стабильная временная шкала без региональных правил
  • выполняется нормализация событий между системами с разными зонами

Ограничения фиксированных смещений

Модель фиксированного смещения не отражает реальную временную политику большинства регионов. В результате:

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

Взаимодействие с форматированием

При форматировании Luxon учитывает текущую зону:

dt.toFormat('yyyy-LL-dd HH:mm ZZZZ');
  • ZZZZ отображает смещение
  • строка не содержит информации о регионе
  • результат зависит от выбранной зоны DateTime

Обработка входных данных с оффсетами

ISO-строки с оффсетом автоматически создают фиксированную зону:

DateTime.fromISO('2026-01-01T10:00:00-04:00');

В этом случае:

  • зона создаётся автоматически
  • оффсет фиксируется как часть объекта
  • дальнейшие вычисления ведутся относительно UTC

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

Даже при разных фиксированных смещениях сравнение происходит по UTC:

const a = DateTime.fromISO('2026-01-01T10:00:00+02:00');
const b = DateTime.fromISO('2026-01-01T09:00:00+01:00');

a.equals(b); // true

Оба значения указывают на один и тот же момент времени, несмотря на разные смещения.