← Назад к вопросам
Какая разница с московским временем?
1.0 Junior🔥 261 комментариев
#Soft skills и опыт работы
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI29 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Работа с московским временем в Node.js Backend
В backend разработке работа с временем и таймзонами — критический вопрос, особенно для русских сервисов. Вот полный разбор:
1. Основные концепции
Текущее время и московский timezone:
import { DateTime } from 'luxon';
// Московский timezone (MSK, UTC+3)
const moscow = 'Europe/Moscow';
// Получить текущее время
const nowUTC = new Date(); // UTC время
const nowMoscow = DateTime.now().setZone('Europe/Moscow');
// UTC: 2024-01-15 10:00:00
// Moscow: 2024-01-15 13:00:00 (UTC+3)
// Разница: 3 часа вперёд
Стандартная разница:
Moscow (MSK): UTC+3 (год-круглый, без летнего времени)
Примеры:
- Лондон (GMT): MSK на 3 часа вперёд
- Нью-Йорк (EST): MSK на 8 часов вперёд
- Нью-Йорк (EDT): MSK на 7 часов вперёд
- Пекин (CST): MSK на 5 часов позади
2. Best Practices для backend
Правило 1: Храни всё в UTC
// ✅ Правильно — храни в БД в UTC
const userCreatedAt = new Date(); // UTC
await db.users.create({
id: '123',
createdAt: userCreatedAt, // UTC
name: 'Иван'
});
// ❌ Неправильно — не храни московское время в БД
const moscowNow = new Date();
moscowNow.setHours(moscowNow.getHours() + 3); // Не делай так!
Правило 2: Конвертируй только при отправке пользователю
import { DateTime } from 'luxon';
class UserService {
// В сервисе работаю с UTC
async getUser(id: string) {
const user = await db.users.findById(id);
return user; // createdAt в UTC
}
}
// В контроллере/API конвертирую для пользователя
export function formatUserResponse(user: User) {
return {
id: user.id,
name: user.name,
// Конвертируем для клиента (москов время)
createdAt: DateTime.fromJSDate(user.createdAt)
.setZone('Europe/Moscow')
.toISO(), // "2024-01-15T13:00:00.000+03:00"
};
}
3. Примеры с популярными библиотеками
Date-fns (рекомендуется):
import { formatInTimeZone, fromZonedTime, toZonedTime } from 'date-fns-tz';
// UTC → Moscow
const utcDate = new Date('2024-01-15T10:00:00Z');
const moscowTime = toZonedTime(utcDate, 'Europe/Moscow');
console.log(moscowTime); // 2024-01-15 13:00:00 (локальное время ПК)
// Moscow → UTC (когда пользователь вводит московское время)
const userInput = new Date('2024-01-15T13:00:00'); // Пользователь вводит московское
const utc = fromZonedTime(userInput, 'Europe/Moscow');
console.log(utc); // 2024-01-15T10:00:00Z
// Форматирование для вывода
const formatted = formatInTimeZone(utcDate, 'Europe/Moscow', 'dd.MM.yyyy HH:mm:ss');
console.log(formatted); // "15.01.2024 13:00:00"
Luxon (альтернатива):
import { DateTime } from 'luxon';
// UTC → Moscow
const utcDate = DateTime.utc(2024, 1, 15, 10, 0, 0);
const moscow = utcDate.setZone('Europe/Moscow');
console.log(moscow.toISO()); // "2024-01-15T13:00:00.000+03:00"
// Moscow → UTC
const moscowDate = DateTime.fromISO('2024-01-15T13:00:00', { zone: 'Europe/Moscow' });
const utc = moscowDate.toUTC();
console.log(utc.toISO()); // "2024-01-15T10:00:00.000Z"
// Красиво форматировать на русском
const formatted = moscow.setLocale('ru').toLocaleString(DateTime.DATETIME_FULL);
console.log(formatted); // "15 января 2024 г., 13:00"
4. Работа с API и формами
Когда пользователь вводит московское время:
// Фронтенд отправляет: "2024-01-15T14:30:00" (московское время)
// Backend должен интерпретировать как Moscow time
router.post('/api/events', (req, res) => {
const { title, scheduledAt } = req.body;
// ❌ Неправильно
// const utc = new Date(scheduledAt); // Интерпретирует как UTC!
// ✅ Правильно
const utc = fromZonedTime(new Date(scheduledAt), 'Europe/Moscow');
await db.events.create({
title,
scheduledAt: utc // Сохраняем UTC
});
res.json({ success: true });
});
Отправка времени пользователю:
router.get('/api/events/:id', (req, res) => {
const event = await db.events.findById(req.params.id);
// Конвертируем для пользователя
const moscowTime = toZonedTime(event.scheduledAt, 'Europe/Moscow');
res.json({
id: event.id,
title: event.title,
// Отправляем московское время для отображения
scheduledAt: formatInTimeZone(event.scheduledAt, 'Europe/Moscow', 'yyyy-MM-dd HH:mm:ss'),
// Или ISO с таймзоной
scheduledAtISO: toZonedTime(event.scheduledAt, 'Europe/Moscow').toISOString()
});
});
5. Ошибки и подводы
Ошибка 1: Прямое преобразование часов
// ❌ НИКОГДА не делай так
const now = new Date();
now.setHours(now.getHours() + 3); // Это ломает DST и неправильно!
// ✅ Используй библиотеки
const utc = new Date();
const moscow = toZonedTime(utc, 'Europe/Moscow');
Ошибка 2: Предполагать локальное время клиента
// ❌ Неправильно
const userTime = new Date('2024-01-15T14:00:00'); // На каком timezone?
// ✅ Правильно — явно указываешь timezone
const userTime = fromZonedTime(
new Date('2024-01-15T14:00:00'),
'Europe/Moscow'
);
Ошибка 3: Забыть про DST
// Московское время НЕ меняется на летнее/зимнее
// Но если ты работаешь с другими странами — помни про DST!
const london = 'Europe/London'; // Меняется на летнее время
const moscow = 'Europe/Moscow'; // НЕ меняется
6. Unit тесты с таймзонами
describe('EventService', () => {
it('should schedule event for moscow timezone', () => {
// Пользователь вводит московское время
const userInput = '2024-06-15T14:00:00'; // 14:00 Moscow
// Конвертируем в UTC для сохранения
const utc = fromZonedTime(new Date(userInput), 'Europe/Moscow');
// В UTC это будет 11:00 (14:00 - 3 часа)
expect(utc.getHours()).toBe(11);
expect(utc.getMinutes()).toBe(0);
});
it('should display event in moscow timezone', () => {
// В БД хранится: "2024-06-15T11:00:00Z" (UTC)
const utcDate = new Date('2024-06-15T11:00:00Z');
// Конвертируем для отображения
const moscow = toZonedTime(utcDate, 'Europe/Moscow');
expect(moscow.getHours()).toBe(14);
expect(moscow.getMinutes()).toBe(0);
});
});
7. Рекомендации
| Задача | Решение |
|---|---|
| Получить текущее UTC время | new Date() или DateTime.utc() |
| Показать московское время | toZonedTime(date, 'Europe/Moscow') |
| Парсить московское время от пользователя | fromZonedTime(date, 'Europe/Moscow') |
| Форматировать для вывода | formatInTimeZone(date, 'Europe/Moscow', format) |
| Сравнение времён | Всегда сравнивай UTC значения |
Итоговое правило: храни всё в UTC, конвертируй только на границах (API, UI). Moscow всегда UTC+3, без изменений на летнее время.