В JavaScript объект даты представляет собой момент времени в виде количества миллисекунд, прошедших с Unix-эпохи (UTC). Любая «зона времени» в стандартной модели не изменяет саму дату, а лишь влияет на её интерпретацию при форматировании. Именно этот принцип лежит в основе всех операций конвертации между временными зонами через Intl API.
Внутреннее хранение:
Date всегда хранит абсолютное время (UTC
timestamp)Следствие: прямой «перевод даты из одной зоны в другую» в виде
изменения объекта Date отсутствует. Вместо этого происходит
форматирование одного и того же момента времени в разных контекстах.
Основной инструмент — Intl.DateTimeFormat с параметром
timeZone.
const date = new Date("2026-05-26T12:00:00Z");
const formatterNY = new Intl.DateTimeFormat("en-US", {
timeZone: "America/New_York",
dateStyle: "full",
timeStyle: "long"
});
const formatterTokyo = new Intl.DateTimeFormat("en-US", {
timeZone: "Asia/Tokyo",
dateStyle: "full",
timeStyle: "long"
});
console.log(formatterNY.format(date));
console.log(formatterTokyo.format(date));
Один и тот же момент времени отображается как разные локальные представления.
Прямого преобразования «из зоны A в зону B» не требуется: выполняется двойное форматирование одного и того же timestamp.
const date = new Date("2026-05-26T12:00:00Z");
function formatInZone(date, timeZone) {
return new Intl.DateTimeFormat("en-GB", {
timeZone,
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
hour12: false
}).format(date);
}
const inBerlin = formatInZone(date, "Europe/Berlin");
const inSydney = formatInZone(date, "Australia/Sydney");
Результат — две строки, представляющие один и тот же момент в разных временных зонах.
const zones = Intl.supportedValuesOf("timeZone");
Это позволяет строить интерфейсы выбора зон или системы сравнения.
Для более сложной конвертации используется
formatToParts, позволяющий извлекать компоненты даты.
const formatter = new Intl.DateTimeFormat("en-US", {
timeZone: "Asia/Tokyo",
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
hour12: false
});
const parts = formatter.formatToParts(new Date());
console.log(parts);
Структура включает:
Это используется для построения собственных моделей отображения и ручной реконструкции строк.
Часто требуется не только отобразить, но и получить строку, соответствующую локальному времени другой зоны.
Пример функции:
function convertToTimeZoneString(date, targetTimeZone) {
const formatter = new Intl.DateTimeFormat("sv-SE", {
timeZone: targetTimeZone,
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
hour12: false
});
return formatter.format(date).replace(" ", "T");
}
Использование формата sv-SE полезно, так как он
возвращает структурированный ISO-подобный результат.
Intl API не предоставляет встроенного механизма:
Причина: неоднозначность локальных представлений.
Решение строится через:
Корректная модель конвертации между зонами:
const date = new Date(Date.UTC(2026, 4, 26, 12, 0, 0));
const tz1 = new Intl.DateTimeFormat("en-US", {
timeZone: "America/Los_Angeles",
hour: "2-digit",
minute: "2-digit"
});
const tz2 = new Intl.DateTimeFormat("en-US", {
timeZone: "Europe/Moscow",
hour: "2-digit",
minute: "2-digit"
});
Обе строки основаны на одном UTC значении.
Разница между зонами не является константой из-за летнего времени.
Пример:
Europe/Berlin может быть UTC+1 или UTC+2America/New_York может быть UTC-5 или UTC-4Следовательно:
Хотя прямого API нет, смещение можно вычислить через сравнение частей.
function getOffsetMinutes(date, timeZone) {
const utc = new Date(date.toLocaleString("en-US", { timeZone: "UTC" }));
const zoned = new Date(date.toLocaleString("en-US", { timeZone }));
return (zoned - utc) / 60000;
}
Метод используется как приближённый, но требует осторожности.
Типичный сценарий — панель сравнения времени:
const zones = [
"UTC",
"Europe/London",
"Europe/Berlin",
"Asia/Tokyo",
"America/New_York"
];
const now = new Date();
const result = zones.map(zone => {
return {
zone,
time: new Intl.DateTimeFormat("en-GB", {
timeZone: zone,
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
hour12: false
}).format(now)
};
});
Для хранения и передачи данных используется:
Date.toISOString()const iso = new Date().toISOString();
Любая конвертация между зонами затем выполняется исключительно на этапе отображения.
function convertBetweenZones(date, fromZone, toZone) {
const intermediate = new Intl.DateTimeFormat("sv-SE", {
timeZone: fromZone,
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
second: "2-digit"
}).format(date).replace(" ", "T");
const parsed = new Date(intermediate + "Z");
return new Intl.DateTimeFormat("sv-SE", {
timeZone: toZone,
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
second: "2-digit"
}).format(parsed);
}
Модель опирается на промежуточное UTC-представление.
Эти ограничения делают Intl API ориентированным на форматирование, а не на математическую модель временных зон.