
Путаница с датами начинается, когда момент времени, календарный день и местное расписание хранят одинаковой строкой. Для начала определите, что означает поле. Момент старта онлайн-события можно показать в разных поясах. Дату рождения нельзя бездумно превращать в «полночь UTC», а затем сдвигать при отображении.
Один момент, два представления
example.js
function formatMoment(iso, timeZone) {
const date = new Date(iso);
if (Number.isNaN(date.getTime())) throw new RangeError('Неверная дата');
return new Intl.DateTimeFormat('ru-RU', {
timeZone, dateStyle: 'medium', timeStyle: 'short'
}).format(date);
}
const instant = '2026-01-15T18:00:00Z';
console.log(formatMoment(instant, 'Europe/Moscow'));
console.log(formatMoment(instant, 'Asia/Krasnoyarsk'));
console.assert(new Date(instant).toISOString() === instant.replace('00Z', '00.000Z'));
Пример запускается в современной среде JavaScript, например node example.js. Строка с Z явно задаёт UTC. Для выбранного условного дня получится 21:00 по Москве и 01:00 следующего дня по Красноярску. Точное оформление строки зависит от локализационных данных среды, поэтому тестировать лучше смысловые части, а не пробелы и пунктуацию.
| Что сравнить | На что смотреть | Что сделать |
|---|---|---|
| Момент | Событие происходит одновременно для всех | Хранить однозначное значение и форматировать в нужном поясе |
| Календарный день | Дата без времени суток | Не добавлять случайный часовой пояс |
| Местное расписание | Например, занятие каждую неделю в городе | Хранить правило и именованный пояс отдельно |
| Отображаемая строка | Представление для человека | Не использовать как машинный формат обмена |
Не делайте пояс постоянной ручной поправкой
Прибавление нескольких часов к timestamp меняет сам момент, а не только его вид. Для отображения используйте timeZone в Intl.DateTimeFormat. MDN описывает этот объект как локализованный форматировщик; он не должен подменять модель расписания. Недопустимое имя пояса тоже может завершиться ошибкой, поэтому внешнее значение нуждается в проверке и обработке.
- Проверить момент около смены календарного дня.
- Проверить неверную входную дату.
- Проверить разные пояса при одинаковом исходном моменте.
- Не сравнивать локализованные строки как надёжные даты.
Укажите договорённость в данных
В API поле scheduledAt может означать момент, а поле localDate — календарную дату. Эти значения лучше называть явно и описывать в контракте. Для повторяющегося расписания нужны правила переноса и изменения поясов, которые этот короткий пример не реализует. Не расширяйте учебную функцию до календарного движка молча.
Вопросы и ответы
Можно ли хранить «15.01.2026 18:00»?
Без дополнительного контракта непонятен пояс и формат. Для обмена нужен однозначный формат, для человека — отдельное отображение.
Почему не прибавить нужные часы?
Это изменит момент и легко создаст повторный сдвиг. Форматировщик умеет менять представление без такой подмены.
Что проверяет Invalid Date?
Только невозможность разобрать значение. Это не полноценная проверка всех бизнес-правил расписания.
Гарантирует ли локаль ru-RU московский пояс?
Нет. Язык оформления и часовой пояс задают разные свойства.
Источники: developer.mozilla.org.




