Как конвертировать время в разные часовые пояса через timestamp
Практическое руководство: переводим UTC в московское время, конвертируем дату в Unix timestamp и обратно для синхронизации в системах
Вчера коллега из Сан-Франциско прислал timestamp 1704124800 и попросил проверить, почему пользователь из Москвы жалуется на неправильное время в логах. Оказалось, что сервер отдавал Unix timestamp, а фронтенд конвертировал его в локальную зону без учёта смещения. Разбираемся, как правильно работать с временем через timestamp и не терять часы при переводе между поясами.
Почему timestamp решает проблему часовых поясов
Unix timestamp — это количество секунд с 1 января 1970 года UTC. Главное свойство: число одинаковое для всех, независимо от географии. Когда в Москве полночь 2 января 2024 года, в Лондоне ещё 9 вечера 1 января, но timestamp у этого момента будет один — 1704150000.
Три причины использовать timestamp:
- Хранишь одно число вместо строки с датой и смещением
- API возвращает timestamp — клиент сам конвертирует в свой пояс
- Сравнение времени работает как обычное сравнение чисел
Ошибка начинается, когда разработчик получает timestamp и применяет к нему смещение дважды: один раз в библиотеке (автоматически), второй — вручную.
Конвертация UTC в московское время
Москва — это UTC+3. Берём timestamp 1704124800 (это 1 января 2024, 22:00 UTC):
const timestamp = 1704124800;
const date = new Date(timestamp * 1000); // JavaScript требует миллисекунды
// Автоматическая конвертация в локальный пояс браузера
console.log(date.toLocaleString('ru-RU', { timeZone: 'Europe/Moscow' }));
// Выведет: 02.01.2024, 01:00:00
В Python подход похожий:
from datetime import datetime, timezone
import pytz
timestamp = 1704124800
utc_time = datetime.fromtimestamp(timestamp, tz=timezone.utc)
moscow_tz = pytz.timezone('Europe/Moscow')
moscow_time = utc_time.astimezone(moscow_tz)
print(moscow_time.strftime('%Y-%m-%d %H:%M:%S %Z'))
# 2024-01-02 01:00:00 MSK
Важно: fromtimestamp() без второго аргумента вернёт время в локальном поясе сервера, а это может быть что угодно.
Преобразование даты в Unix timestamp
Обратная задача: у тебя строка "2024-01-15 14:30:00" в московском времени, нужен timestamp для API.
JavaScript:
// Явно указываем часовой пояс
const dateStr = '2024-01-15T14:30:00';
const moscowDate = new Date(dateStr + '+03:00'); // Добавляем смещение
const timestamp = Math.floor(moscowDate.getTime() / 1000);
console.log(timestamp); // 1705323000
Без явного смещения new Date() интерпретирует строку как локальное время браузера, что даст разные результаты в Москве и Калифорнии.
Python с учётом пояса:
from datetime import datetime
import pytz
moscow_tz = pytz.timezone('Europe/Moscow')
date_str = '2024-01-15 14:30:00'
naive_dt = datetime.strptime(date_str, '%Y-%m-%d %H:%M:%S')
moscow_dt = moscow_tz.localize(naive_dt)
timestamp = int(moscow_dt.timestamp())
print(timestamp) # 1705323000
Метод localize() привязывает "наивное" время (без пояса) к конкретной зоне.
Синхронизация времени между системами
Реальный кейс: мобильное приложение синхронизирует задачи с бэкендом. Пользователь создаёт задачу в 10 утра по Токио, коллега в Берлине должен увидеть правильное локальное время.
Алгоритм:
- Клиент конвертирует локальную дату в timestamp
- Отправляет на сервер только timestamp
- Сервер хранит timestamp в базе (UNIX_TIMESTAMP в MySQL или INTEGER в SQLite)
- При запросе сервер возвращает timestamp
- Клиент конвертирует в свой часовой пояс
Пример API-ответа:
{
"task_id": 12345,
"title": "Созвон с командой",
"created_at": 1705305600,
"deadline": 1705392000
}
На клиенте (TypeScript):
interface Task {
task_id: number;
title: string;
created_at: number;
deadline: number;
}
function formatTaskDeadline(task: Task): string {
const date = new Date(task.deadline * 1000);
return date.toLocaleString('ru-RU', {
year: 'numeric',
month: 'long',
day: 'numeric',
hour: '2-digit',
minute: '2-digit'
});
}
Никакого ручного добавления/вычитания часов — браузер делает это сам через API Intl.
Распространённые ошибки при работе с временем
Ошибка 1: Смешивание timestamp и миллисекунд
JavaScript оперирует миллисекундами, большинство бэкендов — секундами. Забыл умножить/разделить на 1000 — получил дату в 1970 году или в 55000 году.
Ошибка 2: Игнорирование летнего времени
В Москве с 2014 года нет перехода на летнее время, но в США/Европе переходы есть. Библиотека учитывает это автоматически, если используешь названия поясов (America/New_York), а не фиксированные смещения (UTC-5).
Ошибка 3: Парсинг строк без timezone
// Плохо
const date1 = new Date('2024-01-15 14:30:00');
// Браузер угадывает формат и пояс
// Хорошо
const date2 = new Date('2024-01-15T14:30:00+03:00');
// Явное указание ISO 8601 с поясом
Ошибка 4: Хранение времени в локальном формате
База хранит "2024-01-15 14:30:00" без указания пояса. При миграции сервера из датацентра в Амстердаме в Сингапур все записи сместятся. Храни timestamp или используй TIMESTAMP WITH TIME ZONE в PostgreSQL.
Практические инструменты для работы
Когда отлаживаешь интеграцию или проверяешь API, удобно быстро конвертировать значения без запуска кода. Для перевода даты и времени в Unix timestamp и обратно есть Конвертер Unix Timestamp — вставляешь число, получаешь человекочитаемую дату с учётом пояса. Если работаешь с URL-параметрами, где дата передаётся строкой, пригодится URL энкодер/декодер для правильного экранирования символов вроде пробелов и двоеточий. Для проверки JSON-ответов API с полями времени используй JSON форматтер — он подсветит структуру и покажет, где именно лежат timestamp-поля.
Храни время в Unix timestamp, конвертируй на клиенте, явно указывай часовые пояса в коде — и пользователи из разных городов увидят правильное локальное время без костылей.