Форматирование и преобразование времени в JavaScript: типичные ошибки
Научитесь форматировать и преобразовывать время в JavaScript без сюрпризов: метки времени, ISO-строки, часовые пояса, летнее время, правила парсинга и надёжные шаблоны.

Что обычно идёт не так с временем в JavaScript
Ошибки с временем в JavaScript редко выглядят как «часы показывают неправильно». Чаще это маленькие сбои: дата, корректная на вашем ноутбуке, но неверная на машине коллеги; ответ API, который выглядит нормально, пока его не отобразить в другой временной зоне; или отчёт, «сдвинутый на один» вокруг сезонного перехода времени.
Наиболее типичные симптомы
Обычно вы заметите одно (или несколько) из следующих:
- Сдвиг на час: особенно вокруг перехода на летнее/зимнее время или когда значение случайно конвертируется между локальным временем и UTC.\n- Сдвиг на день: значение «только дата» (например, «2025-12-23») отображается как предыдущий/следующий день в зависимости от часового пояса.\n- Неправильный часовой пояс: время выглядит верно, но смещение (например,
+02:00) отличается от ожидаемого.\n- Непоследовательное форматирование: «работает в Chrome» но выглядит иначе в Safari, или сервер и браузер по-разному парсят строку.
Почему это происходит: «время» может означать разное
Большая часть проблем в том, что слово время может обозначать разные концепции:
- Момент (instant): конкретный момент во всём мире (например,
"2025-12-23T10:00:00Z"). Это то, что обычно нужно для логов, событий и хранения в API.\n- Календарная дата: день в календаре без часового пояса (например, день рождения, дата счёта). Обращение с ней как с моментом может сдвинуть её на соседний день.\n- Показанное локальное время (wall-clock time): «9:00 в Берлине», которое зависит от правил часового пояса и переходов на летнее/зимнее время.
Встроенный Date в JavaScript пытается охватить всё это, но в основе представляет момент времени, при этом постоянно подталкивая вас к локальному отображению, что делает случайные преобразования лёгкими.
На чём сосредоточена эта статья
Это руководство предельно практично: как получить предсказуемые преобразования в браузерах и на серверах, как выбирать более безопасные форматы (например, ISO 8601) и как замечать классические ловушки (секунды против миллисекунд, UTC против локального, и различия парсинга). Цель не в теории — а в том, чтобы было меньше «почему это сдвинулось?» сюрпризов.
Типы представления времени: метка времени, Date и строка
Ошибки с временем в JavaScript часто начинаются с смешивания представлений, которые выглядят взаимозаменяемыми, но таковыми не являются.
Три представления, которые вы увидите чаще всего
1) Эпоха в миллисекундах (число)
Простое число вроде 1735689600000 обычно означает «миллисекунды с 1970-01-01T00:00:00Z». Оно представляет момент времени без форматирования и часового пояса.
2) Объект Date (обёртка вокруг момента)
Date хранит тот же тип момента, что и метка времени. Путаница в том, что при выводе Date JavaScript форматирует его по локальным правилам окружения, если вы не указали иное.
3) Форматированная строка (для человека)
Строки вроде "2025-01-01", "01/01/2025 10:00" или "2025-01-01T00:00:00Z" — это не одно и то же. Некоторые однозначны (ISO 8601 с Z), другие зависят от локали, а некоторые вообще не содержат информации о часовом поясе.
«Момент времени» vs «показ для человека»
- Момент времени: «этот точный момент глобально» (лучше хранить как миллисекунды эпохи или ISO-строку в UTC).\n- Показ для человека: «что должен увидеть пользователь» (зависит от локали и часового пояса).
Один и тот же момент может отображаться по-разному в разных часовых поясах:
const instant = new Date("2025-01-01T00:00:00Z");
instant.toLocaleString("en-US", { timeZone: "UTC" });
// "1/1/2025, 12:00:00 AM"
instant.toLocaleString("en-US", { timeZone: "America/Los_Angeles" });
// "12/31/2024, 4:00:00 PM" (предыдущий день)
Выберите один «источник истины»
Выберите одно внутреннее представление (обычно миллисекунды эпохи или UTC ISO 8601) и придерживайтесь его по всему приложению и API. Конвертируйте в/из Date и форматированные строки только на границах: при парсинге входных данных и при отображении в UI.
Метки времени: секунды против миллисекунд (легко перепутать)
«Метка времени» обычно означает эпоху (Unix time): отсчёт времени с 1970-01-01 00:00:00 UTC. Загвоздка в том, что разные системы считают в разных единицах.
Date в JavaScript — источник большинства недоразумений, потому что он использует миллисекунды. Многие API, БД и логи используют секунды.
Правило на заметку
- Unix timestamp (секунды):
1704067200\n- JavaScript timestamp (миллисекунды):1704067200000
Один и тот же момент, но версия в миллисекундах имеет три дополнительных цифры.
Безопасные преобразования (секунды ↔ миллисекунды)
Используйте явное умножение/деление, чтобы явно обозначить единицу:
// seconds -> Date
const seconds = 1704067200;
const d1 = new Date(seconds * 1000);
// milliseconds -> Date
const ms = 1704067200000;
const d2 = new Date(ms);
// Date -> seconds
const secondsOut = Math.floor(d2.getTime() / 1000);
// Date -> milliseconds
const msOut = d2.getTime();
Классическая ошибка: передать секунды в Date()
Это выглядит разумно, но неправильно, когда ts в секундах:
const ts = 1704067200; // seconds
const d = new Date(ts); // WRONG: treated as milliseconds
Результатом будет дата в 1970 году, потому что 1,704,067,200 миллисекунд — это лишь около 19 дней после эпохи.
Быстрая валидация и отладочные проверки
Когда вы не уверены в единице, добавьте простые проверки:
function asDateFromUnknownEpoch(x) {
// crude heuristic: seconds are ~1e9-1e10, milliseconds are ~1e12-1e13
if (x < 1e11) return new Date(x * 1000); // assume seconds
return new Date(x); // assume milliseconds
}
const input = Number(valueFromApi);
console.log({ input, digits: String(Math.trunc(input)).length });
console.log('as ISO:', asDateFromUnknownEpoch(input).toISOString());
Если количество «цифр» примерно 10 — вероятно секуды. Если ~13 — вероятно миллисекунды. Также во время отладки выводите toISOString(): это однозначно и помогает быстро заметить ошибки с единицами.
Локальное время vs UTC: почему ваш вывод смещается
Date в JavaScript может хранить один момент времени, но отображать его в разных часовых поясах.
Внутри Date — по сути «миллисекунды с эпохи» (1970-01-01T00:00:00Z). Это число представляет момент в UTC. Сдвиг появляется, когда вы просите JavaScript отформатировать этот момент как локальное время (по настройкам компьютера/сервера) или как UTC.
Локальные геттеры vs UTC-геттеры
Многие API Date имеют локальные и UTC-варианты. Они возвращают разные числа для одного и того же момента:
const d = new Date('2025-01-01T00:30:00Z');
d.getHours(); // hour in *local* time zone
d.getUTCHours(); // hour in UTC
d.toString(); // local time string
d.toISOString(); // UTC (always ends with Z)
Если ваша машина в Нью-Йорке (UTC-5), это UTC-время может выглядеть как «19:30» предыдущего дня локально. На сервере, настроенном на UTC, оно будет «00:30». Один и тот же момент, разное отображение.
Почему логи выглядят «неправильно»
Логи часто используют Date#toString() или неявную интерполяцию Date, что использует локальный часовой пояс окружения. Это означает, что один и тот же код может печатать разные метки времени на вашем ноутбуке, в CI и в продакшене.
Практические рекомендации
Храните и передавайте время в UTC (например, epoch milliseconds или ISO 8601 с Z). Конвертируйте в локаль пользователя только при отображении:
- Для API: предпочитайте
toISOString()или передавайте миллисекунды эпохи - Для UI: форматируйте в часовом поясе пользователя с помощью
Intl.DateTimeFormat
Если вы быстро собираете приложение (например, с workflow в Koder.ai), полезно задать это в соглашениях API с самого начала: ясно именуйте поля (createdAtMs, createdAtIso) и держите сервер (Go + PostgreSQL) и клиент (React) в согласии по тому, что означает каждое поле.
ISO 8601 строки: самый надёжный формат для API
Если нужно передавать даты/время между браузером, сервером и базой данных, ISO 8601 строки — самое безопасное по умолчанию. Они явные, широко поддерживаются и (важно) содержат информацию о часовом поясе.
Используйте явный UTC или явный сдвиг
Два хороших формата для обмена:
- UTC время (рекомендуется, когда локальный часовой пояс не важен):
2025-03-04T12:30:00Z\n- Локальное время со смещением (когда важен локальный показ):2025-03-04T12:30:00+02:00
Что значит Z?\n
Z обозначает Zulu time, другое имя для UTC. То есть 2025-03-04T12:30:00Z — это «12:30 по UTC».
Когда смещения вроде +02:00 важны?\n
Смещения критичны, когда событие привязано к локальному контексту (встречи, бронирования, часы работы). 2025-03-04T12:30:00+02:00 описывает момент, который на два часа опережает UTC, и он не равен 2025-03-04T12:30:00Z.
Избегайте неоднозначных строк дат
Строки вроде 03/04/2025 — ловушка: это 4 марта или 3 апреля? Разные пользователи и окружения интерпретируют по-разному. Предпочитайте 2025-03-04 (ISO дата) или полный ISO datetime.
Безопасный круг (строка → Date → строка)
const iso = "2025-03-04T12:30:00Z";
const d = new Date(iso);
const back = d.toISOString();
console.log(iso); // 2025-03-04T12:30:00Z
console.log(back); // 2025-03-04T12:30:00.000Z
Такое «круговое» поведение именно то, что нужно для API: согласованно, предсказуемо и с учётом часового пояса.
Ловушки парсинга: Date.parse и различия между браузерами
Date.parse() кажется удобным: даёшь строку — получаешь timestamp. Проблема в том, что для всего, что не является однозначным ISO 8601, парсинг опирается на эвристики браузера. Эти эвристики различались между движками и версиями, а значит одна и та же строка может распарситься по-разному (или не распарситься вовсе) в разных окружениях.
Почему Date.parse() может давать разный результат
JavaScript стандартизирует парсинг надёжно только для строк в стиле ISO 8601 (и даже там детали вроде часового пояса важны). Для «удобных» форматов — типа "03/04/2025", "March 4, 2025" или "2025-3-4" — браузеры могут:
- Интерпретировать месяц/день в разном порядке в зависимости от локали\n- Считать отсутствие часового пояса локальным временем в одном движке, но отвергнуть строку в другом\n- Принимать слегка некорректные строки как «достаточно близкие»… пока это не перестанет работать
Если вы не можете предсказать точную форму строки, вы не можете предсказать результат.
Удивительный случай: YYYY-MM-DD
Распространённая ловушка — простая дата "YYYY-MM-DD" (например, "2025-01-15"). Многие разработчики ожидают, что это будет интерпретировано как локальное полуночное время. На практике некоторые окружения трактуют эту форму как UTC полуночь.
Эта разница важна: UTC-полуночь, преобразованная в локальное время, может стать предыдущим днём в отрицательных часовых поясах (например, в Америке) или неожиданно сместить время на часы. Это простой способ получить «почему моя дата сместилась на день?» баг.
Чеклист парсинга: ввод от пользователя vs ввод в сервер
Для входа в API/сервер:
- Предпочитайте полный ISO 8601 с явным часовым поясом, например
2025-01-15T13:45:00Zили2025-01-15T13:45:00+02:00.\n- Обрабатывайте значения только с датой как данные, а не как момент времени. Если это день рождения или срок, храните как простую строку ("YYYY-MM-DD") и не конвертируйте вDate, если вы не определили ожидаемый часовой пояс.
Для ввода от пользователя:
- Не принимайте неоднозначные форматы вроде
03/04/2025, если интерфейс не жестко задаёт смысл.\n- Предпочитайте контролируемые элементы (date pickers), которые выдают известный формат.\n- Если нужно парсить свободный текст, заранее определите и принудительно принимайте конкретные форматы.
Используйте явные правила (не эвристики)
Вместо того чтобы полагаться на Date.parse() и его «разберётся», выберите один из подходов:
- Принимать с серверов только ISO 8601; отвергать всё остальное.\n- Парсить вручную известные форматы (разбивать строку и использовать
new Date(year, monthIndex, day)для локальных дат).\n- Хранить и передавать метки времени (миллисекунды эпохи) для точных моментов и форматировать при отображении.
Когда данные о времени критичны, «на моём компьютере парсится» недостаточно — сделайте правила парсинга явными и согласованными.
Форматирование для людей с Intl.DateTimeFormat
Если ваша цель — «показать дату/время так, как ожидают люди», лучший инструмент в JavaScript — Intl.DateTimeFormat. Он использует правила локали пользователя (порядок, разделители, названия месяцев) и избавляет от хрупкого склеивания строк вроде month + '/' + day.
Почему он лучше ручной сборки строк
Ручное форматирование часто жёстко задаёт американский формат, забывает ведущие нули или даёт путаницу 24/12-часового формата. Intl.DateTimeFormat также явно показывает, в каком часовом поясе вы отображаете — критично, когда данные хранятся в UTC, а UI должен отражать локаль пользователя.
Опции, которые реально пригодятся
Для «красивого» форматирования достаточно dateStyle и timeStyle:
const d = new Date('2025-01-05T16:30:00Z');
// User’s locale + user’s local time zone
console.log(new Intl.DateTimeFormat(undefined, {
dateStyle: 'medium',
timeStyle: 'short'
}).format(d));
// Force a specific time zone (great for event times)
console.log(new Intl.DateTimeFormat('en-GB', {
dateStyle: 'full',
timeStyle: 'short',
timeZone: 'UTC'
}).format(d));
Если нужна постоянная 12/24-часовая система, используйте hour12:
console.log(new Intl.DateTimeFormat('en-US', {
hour: 'numeric',
minute: '2-digit',
hour12: true
}).format(d));
Практичный паттерн для UI
Выберите одну функцию форматирования для каждого «типа» метки времени в интерфейсе (время сообщения, запись лога, начало события) и делайте решение о timeZone намеренным:
- Используйте локальное время для «когда это произошло для меня».\n- Используйте фиксированный часовой пояс (часто UTC) для аудита, серверных событий или координации между командами.
Так вы получите последовательный, дружественный к локали вывод без поддержки хрупкого набора собственных формат-строк.
Летнее время: скрытая ошибка «минус/плюс час»
Летнее/зимнее время (DST) — это когда в часовом поясе меняется смещение UTC (обычно на один час) в определённые даты. Сложность в том, что DST не только «меняет смещение» — оно меняет саму существовательность локальных времён.
Отсутствующие и дублирующиеся локальные времена
Когда часы переводят вперёд (spring forward), диапазон локальных времён просто не случается. Например, в некоторых регионах часы прыгают с 01:59 на 03:00, поэтому 02:30 локального времени «не существует».
Когда часы переводят назад (fall back), диапазон локальных времён случается дважды. Например, 01:30 может произойти один раз до перевода и один раз после — то же локальное время может соответствовать двум разным моментам.
Добавить 24 часа vs «тот же локальный час завтра»
Эти операции не эквивалентны вокруг переходов DST:
- Добавить 24 часа: «ровно через 24 * 60 * 60 секунд»\n- Завтра в то же локальное время: «завтра в 9:00 в этом часовом поясе»
Если сегодня начинается DST, «завтра в 9:00» может быть всего через 23 часа. Если сегодня заканчивается DST, это может быть 25 часов.
// Scenario: schedule “same local time tomorrow”
const d = new Date(2025, 2, 8, 9, 0); // Mar 8, 9:00 local
const plus24h = new Date(d.getTime() + 24 * 60 * 60 * 1000);
const nextDaySameLocal = new Date(d);
nextDaySameLocal.setDate(d.getDate() + 1);
// Around DST, plus24h and nextDaySameLocal can differ by 1 hour.
Почему setHours может удивлять
Если вы делаете date.setHours(2, 30, 0, 0) в день «spring forward», JavaScript может нормализовать его в другое валидное время (часто 03:30), потому что 02:30 локально не существует.
Более безопасные подходы
- Делайте арифметику в UTC для длительностей: используйте миллисекунды эпохи и UTC-методы.\n- Для локального планирования явно указывайте намерение: «завтра в 9:00 локально» используйте календарные операции (
setDate), а не простое добавление миллисекунд.\n- При обмене временем через API предпочитайте ISO 8601 с оффсетом илиZ, чтобы момент был однозначен.
Длительности vs Даты: не используйте Date для таймера
Частая ошибка — использовать Date для представления того, что не является календарным моментом.
Метка времени отвечает на вопрос «когда это произошло?» (конкретный момент вроде 2025-12-23T10:00:00Z). Длительность отвечает на вопрос «как долго?» (например, «3 минуты 12 секунд»). Это разные концепции, и смешение их приводит к путанной арифметике и неожиданным эффектам с часовыми поясами/DST.
Почему Date — не тот инструмент для длительностей
Date всегда представляет точку на временной шкале относительно эпохи. Если вы храните «90 секунд» как Date, вы фактически храните «1970-01-01 плюс 90 секунд» в некотором часовом поясе. Форматирование может внезапно дать 01:01:30, сместиться на час или показать дату, которой вы не ожидали.
Для длительностей предпочитайте обычные числа:
- Храните длительности в секундах или миллисекундах (выберите единицу и придерживайтесь её).\n- Делайте арифметику с числами.\n- Конвертируйте в отображаемую строку только в конце.
Преобразование секунд в HH:mm:ss
Простой форматтер, подходящий для таймеров и длительностей медиа:
function formatHMS(totalSeconds) {
const s = Math.max(0, Math.floor(totalSeconds));
const hh = String(Math.floor(s / 3600)).padStart(2, "0");
const mm = String(Math.floor((s % 3600) / 60)).padStart(2, "0");
const ss = String(s % 60).padStart(2, "0");
return `${hh}:${mm}:${ss}`;
}
formatHMS(75); // "00:01:15" (countdown timer)
formatHMS(5423); // "01:30:23" (media duration)
Если конвертируете из минут — сначала умножьте (minutes * 60) и держите значение числовым до момента рендеринга.
Сравнение, сортировка и диапазоны без сюрпризов
При сравнении времени в JavaScript безопаснее сравнивать числа, а не отформатированный текст. Date объект по сути оборачивает числовую метку (миллисекунды), поэтому сравнения должны сводиться к «число против числа».
Безопасные сравнения (побеждают метки времени)
Используйте getTime() (или Date.valueOf()) для надёжного сравнения:
const a = new Date('2025-01-10T12:00:00Z');
const b = new Date('2025-01-10T12:00:01Z');
if (a.getTime() < b.getTime()) {
// a is earlier
}
// Also works:
if (+a < +b) {
// unary + calls valueOf()
}
Избегайте сравнения форматированных строк вроде "1/10/2025, 12:00 PM" — они зависят от локали и не отсортируют корректно. Главное исключение — ISO 8601 строки в одном формате и часовом поясе (например, все ...Z), которые сравниваются лексикографически.
Сортировка и фильтрация по диапазону
Сортировка по времени проста, если сортировать по миллисекундам эпохи:
items.sort((x, y) => new Date(x.createdAt).getTime() - new Date(y.createdAt).getTime());
Фильтрация внутри диапазона — та же идея:
const start = new Date('2025-01-01T00:00:00Z').getTime();
const end = new Date('2025-02-01T00:00:00Z').getTime();
const inRange = items.filter(i => {
const t = new Date(i.createdAt).getTime();
return t >= start && t < end;
});
«Начало/конец дня» (локально vs UTC)
«Начало дня» зависит от того, имеете ли вы в виду локальное время или UTC:
// Local start/end of day
const d = new Date(2025, 0, 10); // Jan 10 in local time
const localStart = new Date(d.getFullYear(), d.getMonth(), d.getDate(), 0, 0, 0, 0);
const localEnd = new Date(d.getFullYear(), d.getMonth(), d.getDate(), 23, 59, 59, 999);
// UTC start/end of day
const utcStart = new Date(Date.UTC(2025, 0, 10, 0, 0, 0, 0));
const utcEnd = new Date(Date.UTC(2025, 0, 10, 23, 59, 59, 999));
Выберите определение рано и придерживайтесь его везде при сравнении и логике диапазонов.
Чеклист отладки: как диагностировать баг с преобразованием времени
Ошибки с временем кажутся случайными, пока вы не определите что у вас есть (метка? строка? Date?) и где появляется сдвиг (парсинг, конвертация часового пояса, форматирование).
1) Зафиксируйте «три представления» одного и того же момента
Начните с логирования одного и того же значения тремя разными способами. Это быстро покажет, секуды vs миллисекунды, локальное vs UTC или парсинг.
console.log('raw input:', input);
const d = new Date(input);
console.log('toISOString (UTC):', d.toISOString());
console.log('toString (local):', d.toString());
console.log('timezone offset (min):', d.getTimezoneOffset());
На что смотреть:
- Если
toISOString()сильно не тот год (например, 1970 или далёкое будущее) — подозревайте секунды vs миллисекунды.\n- ЕслиtoISOString()выглядит верно, ноtoString()«сдвинут» — вы видите проблему отображения в локальном часовом поясе.\n- ЕслиgetTimezoneOffset()меняется в зависимости от даты — вы пересекаете летнее время.
2) Проверьте окружение: часовой пояс и локаль
Многие «работает у меня» сообщения — просто разные настройки окружения.
- Браузер: проверьте системный часовой пояс и язык браузера. Затем выполните:
console.log(Intl.DateTimeFormat().resolvedOptions());
- Node.js / сервер: подтвердите часовой пояс процесса:
console.log('TZ:', process.env.TZ);
console.log(Intl.DateTimeFormat().resolvedOptions().timeZone);
Если ваш сервер в UTC, а ноутбук в локальном часовом поясе, форматированный вывод будет отличаться, если вы явно не укажете timeZone.
3) Добавьте тесты в тех местах, где время чаще ломается
Напишите юнит-тесты вокруг границ DST и «крайних» времён:
- За час до и после перехода DST в нужной зоне\n- Концы месяца/года и переходы
23:30→00:30\n- Несколько часовых поясов, если продукт их поддерживает
Если вы быстро итеративно разрабатываете, сделайте эти тесты частью начального набора. Например, при генерации React + Go приложения в Koder.ai можно сразу добавить «контракт времени» (пример нагрузок API + проверки парсинга/форматирования), чтобы регрессии ловились до деплоя.
Быстрый предпусковой чеклист
- Входы имеют явный контракт: миллисекунды эпохи или ISO 8601 с оффсетом.\n- Никаких неоднозначных строк вроде
"2025-03-02 10:00".\n- Форматирование всегда указываетlocaleи (при необходимости)timeZone.\n- Тесты покрывают границы DST для целевых регионов.
Рекомендуемые паттерны для надёжной работы со временем
Надёжная работа со временем в JavaScript в основном сводится к выбору «источника истины» и последовательности от хранения до отображения.
Набор простых лучших практик
Храните и вычисляйте в UTC. Локальное время пользователя рассматривайте как деталь представления.
Передавайте даты между системами как ISO 8601 строки с явным оффсетом (предпочтительно Z). Если нужно отправлять числовые эпохи, документируйте единицы и соблюдайте консистентность (миллисекунды — обычный дефолт в JS).
Форматируйте для людей с помощью Intl.DateTimeFormat (или toLocaleString) и указывайте timeZone, когда нужен детерминированный вывод (например, всегда показывать в UTC или в определённом рабочем регионе).
Руководство по решениям: БД vs API vs UI
- База данных: храните момент как UTC (миллисекунды эпохи или тип datetime в UTC). Избегайте «локальных» datetime, если предметная область не требует хранения wall-clock времени (например, «магазин открывается в 09:00»).\n- API: предпочитайте ISO 8601 с
Z(например,2025-12-23T10:15:00Z). Если используете эпохи, дайте полю явное имя вродеcreatedAtMs, чтобы единицы были понятны.\n- UI: берите сохранённый UTC-момент и форматируйте его под локаль пользователя. Для интерфейсов планирования явно указывайте часовой пояс и делайте конвертации явными.
Когда библиотека оправдана
Подумайте о специализированной библиотеке, если вам нужны повторяющиеся события, сложные правила часовых поясов, DST-устойчивая арифметика («тот же локальный час завтра») или много парсинга несогласованных входов. Ценность в более ясных API и меньшем количестве пограничных багов.
Если хотите углубиться, посмотрите другие руководства по времени на /blog. Если оцениваете инструменты или варианты поддержки, см. /pricing.
FAQ
Какой формат меток времени использовать в JavaScript?
Используйте миллисекунды эпохи или строку UTC в формате ISO 8601 как внутренний формат. Преобразуйте значение в локальный формат только при показе человеку.
Почему моя метка времени Unix превращается в дату 1970 года?
JavaScript Date ожидает миллисекунды. Умножьте метку времени Unix в секундах на 1000, прежде чем передавать её в new Date().
Почему одна и та же дата показывает разное время на разных компьютерах?
Объект Date хранит один момент времени, но JavaScript часто отображает его в локальном часовом поясе компьютера. Сравните toISOString() и toString(), чтобы понять, изменились данные или только отображение.
Как не допустить сдвига даты на один день?
Храните дату без времени, например дату рождения или дату счёта, в виде YYYY-MM-DD. Не преобразуйте её в Date, если не указали нужный часовой пояс.
Какой формат даты безопаснее всего для API?
Передавайте полное значение ISO 8601 с Z для UTC, например 2025-03-04T12:30:00Z, или указывайте явное смещение. Избегайте строк вроде 03/04/2025, потому что люди и браузеры могут интерпретировать их по-разному.
Как форматировать даты для пользователей?
Используйте Intl.DateTimeFormat и указывайте timeZone, если интерфейс должен показывать фиксированный часовой пояс. Он форматирует даты в соответствии с локалью пользователя без ручной сборки строк.
Стоит ли использовать Date.parse для дат, введённых пользователем?
Не полагайтесь на него для неформальных или неоднозначных строк. Принимайте от API известный формат ISO или разбирайте контролируемый пользовательский ввод по правилам, которые задаёте сами.
Почему не стоит использовать Date для обратного отсчёта или длительности?
Date обозначает момент на календаре, а длительность лишь количество времени. Храните длительности в секундах или миллисекундах, а число форматируйте при отображении.
Как переход на летнее время влияет на даты в JavaScript?
Для расчётов прошедшего времени используйте миллисекунды эпохи. Для расписаний, таких как «завтра в 9:00 утра» в именованном часовом поясе, используйте календарные операции и проверяйте даты перехода на летнее и зимнее время.
Как быстрее всего отладить ошибку со временем в JavaScript?
Выведите в лог исходные входные данные, toISOString(), toString() и getTimezoneOffset(). Неверное значение ISO часто указывает на проблему разбора или единиц измерения, а другая локальная строка обычно означает разницу в отображении часового пояса.