ttools
датаформатированиепрограммирование

Как форматировать дату: 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): парсинг произвольных форматов

Практические советы

  1. В API передавайте ISO 8601 с UTC: 2024-01-01T14:30:00Z
  2. В базах храните UTC: либо timestamp, либо TIMESTAMP WITH TIME ZONE
  3. Валидируйте ввод: пользователь может написать 32/13/2024
  4. Тестируйте граничные случаи: високосные года, переход на летнее время, 29 февраля
  5. Документируйте формат: в API-описании явно укажите, какой формат ожидается

Если нужно быстро преобразовать дату между форматами или проверить корректность timestamp, попробуйте Unix Timestamp конвертер или Форматтер JSON для работы с API-ответами, содержащими даты. Для кодирования дат в URL-параметрах пригодится URL энкодер/декодер.

Инструменты по теме