JavaScript WindowsLinuxmacOS

JavaScript: дата из ISO-строки смещается на день из-за часового пояса

  • Обновлено
  • Чтение ≈ 3 минуты

Краткий ответ

Дата из ISO-строки сдвигается на предыдущий или следующий день: различайте момент UTC, календарную дату без часового пояса и локальную дату пользователя.

В этой статье
  1. Что происходит и как распознать неисправность
  2. Как отличить причины
  3. Пошаговая диагностика и исправление
  4. Команды и примеры для проверки
  5. Как проверить результат и что делать дальше

#Что происходит и как распознать неисправность

Строка 2026-03-01 — календарная дата; в современных JavaScript new Date("2026-03-01") интерпретируется как полночь UTC, и при выводе в отрицательном часовом поясе день может стать предыдущим. Строка с Z — конкретный UTC-момент. Для дней рождения и сроков без времени лучше хранить саму дату, а не «момент».

#Как отличить причины

Возможная причинаКак узнатьЧто делать
Разные зоны чтения и отображенияДата создана как полночь UTC, а отображена по времени браузера.На компьютерах в разных часовых поясах разные дни.Храните календарную дату строкой YYYY-MM-DD.
toISOString() переводит время в UTCРазработчик получает ISO UTC из локальной полуночи.toISOString().slice(0,10) даёт соседний день.Для локальных полей берите календарные компоненты, а не UTC.
API возвращает момент без offsetВ дате-времени отсутствуют Z или +hh:mm.Клиенты по-разному трактуют исходное назначение.Определите договорённость о временной зоне API.

#Пошаговая диагностика и исправление

  1. Сохраните проблемное значение и ожидаемый деньОткройте страницу, нажмите F12 → «Консоль», выведите исходную ISO-строку до создания Date и зафиксируйте, что она означает: день в календаре или точный момент события. Не исправляйте код, пока не ясно значение; для срока платежа и дня рождения это разные задачи.
  2. Сравните UTC и местную датуВ консоли браузера выполните new Date("2026-03-01").toISOString() и new Date("2026-03-01").toString(). Первая строка содержит Z и UTC, вторая — местную зону. Если календарный день отличается, причина найдена; на компьютере с UTC+3 пример может не проявиться, проверьте тестом с нужным часовым поясом.
  3. Для календарной даты не создавайте объект Date без нуждыЕсли поле означает только дату без времени, храните YYYY-MM-DD, валидируйте формат и показывайте части напрямую либо средствами локализации без перехода между часовыми поясами. Не применяйте к ней toISOString(); UTC там не имеет предметного смысла. Для date-input можно использовать его строковое .value.
  4. Если нужен локальный Date, создавайте его из компонентовИз строки YYYY-MM-DD выделите год, месяц, день и используйте new Date(year, month - 1, day) только тогда, когда требуется локальная дата. Месяц в конструкторе начинается с нуля. Сравните компоненты getFullYear/getMonth/getDate с исходными значениями; если важен только день, строка всё равно надёжнее.
  5. Для события с временем храните реальный моментЕсли API передаёт событие во времени, потребуйте ISO-строку с Z или явным смещением, например 2026-11-02T07:00:00+02:00. Разбирайте через new Date и отображайте локально, указав пользователю часовую зону. Для преобразования в UTC используйте toISOString сознательно, а не как формат «даты без времени».
  6. Проверьте сервер и базу данныхОткройте обработчик API и проверьте, не удаляет ли он смещение и не срезает ли T...Z при сериализации. В тестовом ответе сравните сырой JSON и то, что получает браузер. Если значение календарное, не переводите его на сервере через UTC; если момент — передавайте зону явно.
  7. Проверьте граничные сутки в нескольких поясахВ тестах используйте UTC−8, UTC и UTC+3 (через средства эмуляции часового пояса, если доступны), а также дату рядом с переводом часов. День рождения должен оставаться тем же календарным днём; запись события должна соответствовать одному моменту. Если после изменений нарушились сохранённые даты, откатите преобразование и уточните семантику старых данных.

#Команды и примеры для проверки

Текст
Различайте строковую календарную дату и объект Date как момент времени. Пример можно запускать в консоли браузера.
const calendarDate = "2026-03-01";
const [year, month, day] = calendarDate.split("-").map(Number);
const localDate = new Date(year, month - 1, day);
console.log(calendarDate);               // день как значение
console.log(localDate.getDate());        // 1 в локальной зоне
console.log(new Date(calendarDate).toISOString()); // полночь UTC

#Как проверить результат и что делать дальше

Календарная дата больше не меняется от часового пояса браузера; точные события отображаются в выбранной зоне с правильным днём. Смешивание двух видов значения неизбежно даёт ошибки на границах суток.

Источники и обновления

Последнее обновление статьи: 2 ноября 2026. Версии программ и интерфейсы меняются — если шаги не совпадают с вашей версией, сверяйтесь с документацией производителя.