Как форматировать дату: Unix timestamp, ISO 8601 и локальные форматы
Разбираемся с форматами дат в программировании: timestamp, ISO, RFC и как преобразовать между ними.
Дата и время — одна из самых частых причин багов в веб-разработке. Разработчик в Москве пишет new Date(), сервер в Лондоне сохраняет в базу, пользователь в Токио видит вчерашнее число. Звучит знакомо? Разбираемся, почему существуют разные форматы дат и как конвертировать между ними без потери данных.
Unix timestamp: считаем секунды от 1970 года
Unix timestamp (или Epoch time) — это количество секунд, прошедших с 1 января 1970 года 00:00:00 UTC. Например, 1704067200 — это полночь 1 января 2024 года по UTC.
Почему именно 1970? Историческая случайность: когда создавали Unix, выбрали удобную круглую дату. Теперь это стандарт де-факто.
Преимущества timestamp:
- Компактность: одно число вместо строки
- Независимость от часовых поясов: всегда UTC
- Простота сравнения:
1704067200 > 1704063600понятнее, чем сравнивать строки - Арифметика: прибавить 86400 = добавить сутки
Подводные камни:
- Проблема 2038 года: 32-битный timestamp закончится 19 января 2038 года (переполнение). Решение — 64-битные системы
- Не читается человеком:
1704067200ни о чём не говорит - В JavaScript timestamp в миллисекундах, а не секундах
// JavaScript работает с миллисекундами
const now = Date.now(); // 1704067200000
const seconds = Math.floor(now / 1000); // 1704067200
// Python — секунды
import time
timestamp = int(time.time()) # 1704067200
ISO 8601: международный стандарт
ISO 8601 — формат, который читается и машиной, и человеком: 2024-01-01T00:00:00Z. Буква T разделяет дату и время, Z означает UTC (или можно указать смещение: +03:00).
Полный формат:
2024-01-01T14:30:00+03:00
YYYY-MM-DDTHH:MM:SS±HH:MM
Почему ISO 8601 удобен:
- Сортировка: строки сортируются хронологически без преобразования
- Однозначность: никакой путаницы между американским MM/DD и европейским DD/MM
- Часовой пояс: явно указан, если нужен
Варианты записи:
2024-01-01T00:00:00Z # UTC
2024-01-01T03:00:00+03:00 # Москва (UTC+3)
2024-01-01T00:00:00.000Z # с миллисекундами
2024-01-01 # только дата
В JavaScript встроенная поддержка:
const date = new Date('2024-01-01T00:00:00Z');
console.log(date.toISOString()); // "2024-01-01T00:00:00.000Z"
RFC 2822 и другие текстовые форматы
RFC 2822 (ранее RFC 822) — формат из почтовых заголовков: Mon, 01 Jan 2024 00:00:00 +0000. Встречается в HTTP-заголовках, RSS-лентах, email.
Примеры:
Mon, 01 Jan 2024 14:30:00 +0300
Wed, 15 Nov 2023 09:00:00 GMT
Другие распространённые форматы:
- SQL:
2024-01-01 14:30:00(безT, локальное время или явный timezone) - Американский:
01/01/2024или1/1/24(месяц/день/год) - Европейский:
01.01.2024или01-01-2024(день.месяц.год)
Проблема текстовых форматов — двусмысленность. Что значит 05/06/2024? 5 июня или 6 мая? Поэтому для API и баз данных лучше использовать ISO 8601.
Конвертация между форматами: сохраняем часовой пояс
Главное правило: всегда храните даты в UTC. Конвертируйте в локальное время только при отображении пользователю.
Timestamp → ISO 8601
const timestamp = 1704067200;
const date = new Date(timestamp * 1000); // JS ждёт миллисекунды
console.log(date.toISOString()); // "2024-01-01T00:00:00.000Z"
from datetime import datetime, timezone
timestamp = 1704067200
dt = datetime.fromtimestamp(timestamp, tz=timezone.utc)
print(dt.isoformat()) # "2024-01-01T00:00:00+00:00"
ISO 8601 → Timestamp
const iso = '2024-01-01T00:00:00Z';
const timestamp = Math.floor(new Date(iso).getTime() / 1000);
console.log(timestamp); // 1704067200
from datetime import datetime
iso = "2024-01-01T00:00:00Z"
dt = datetime.fromisoformat(iso.replace('Z', '+00:00'))
timestamp = int(dt.timestamp())
print(timestamp) # 1704067200
Локальное время → UTC
Частая ошибка: забыть указать часовой пояс. JavaScript new Date() без параметров возвращает локальное время браузера.
// ПЛОХО: неясно, какой часовой пояс
const local = new Date('2024-01-01 14:30:00');
// ХОРОШО: явно UTC
const utc = new Date('2024-01-01T14:30:00Z');
// ХОРОШО: явное смещение
const moscow = new Date('2024-01-01T14:30:00+03:00');
В Python используйте timezone.utc или библиотеку pytz:
from datetime import datetime, timezone
# Явно UTC
dt_utc = datetime(2024, 1, 1, 14, 30, tzinfo=timezone.utc)
# Naive datetime (без timezone) — источник багов
dt_naive = datetime(2024, 1, 1, 14, 30) # Избегайте!
Форматирование для пользователя
После получения данных от API (обычно в ISO или timestamp) нужно показать дату в удобном виде. Используйте встроенные возможности языка или библиотеки.
JavaScript Intl.DateTimeFormat:
const date = new Date('2024-01-01T14:30:00Z');
// Локаль пользователя
const formatter = new Intl.DateTimeFormat('ru-RU', {
year: 'numeric',
month: 'long',
day: 'numeric',
hour: '2-digit',
minute: '2-digit',
timeZoneName: 'short'
});
console.log(formatter.format(date)); // "1 января 2024 г., 17:30 МСК"
Библиотеки для сложных задач:
- date-fns (JS): модульная, tree-shakeable
- Day.js (JS): лёгкая альтернатива Moment.js
- python-dateutil (Python): парсинг произвольных форматов
Практические советы
- В API передавайте ISO 8601 с UTC:
2024-01-01T14:30:00Z - В базах храните UTC: либо timestamp, либо
TIMESTAMP WITH TIME ZONE - Валидируйте ввод: пользователь может написать
32/13/2024 - Тестируйте граничные случаи: високосные года, переход на летнее время, 29 февраля
- Документируйте формат: в API-описании явно укажите, какой формат ожидается
Если нужно быстро преобразовать дату между форматами или проверить корректность timestamp, попробуйте Unix Timestamp конвертер или Форматтер JSON для работы с API-ответами, содержащими даты. Для кодирования дат в URL-параметрах пригодится URL энкодер/декодер.