← Назад к вопросам

Какая разница с московским временем?

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, без изменений на летнее время.

Какая разница с московским временем? | PrepBro