Дата и время в Python: практическое руководство по datetime, strftime/strptime и таймзонам
Работа с датой и временем — обязательный навык в реальных проектах: логи, отчёты, напоминания, аналитика. В Python за это отвечает модуль datetime, а с Python 3.9+ — также zoneinfo для таймзон без внешних библиотек. Ниже — практическая выжимка с примерами и советами, чтобы вы уверенно справлялись с датой/временем в любом проекте.
Быстрый старт: создание даты и времени
from datetime import date, time, datetime, timedelta
from zoneinfo import ZoneInfo
# Текущие дата и время
today = date.today()
now_naive = datetime.now() # naive — без таймзоны
now_utc = datetime.now(ZoneInfo("UTC")) # aware — с таймзоной UTC
# Конкретные значения
birthday = date(1995, 7, 14)
meeting = datetime(2025, 3, 21, 14, 30)
# С таймзоной (Москва)
msk = ZoneInfo("Europe/Moscow")
now_msk = datetime.now(msk)
print(today, now_naive, now_utc, now_msk, sep="\n")
В Python бывают два типа datetime: naive (без tzinfo) и aware (с tzinfo). Для надёжной работы в распределённых системах храните время в UTC и переводите в локальную зону только на границе с пользователем.
Форматирование дат: strftime
strftime превращает дату/время в строку по шаблону. Самые полезные спецификаторы: %Y (год), %m (месяц), %d (день), %H:%M:%S (часы, минуты, секунды), %f (микросекунды), %z (смещение таймзоны), %Z (имя зоны).
from datetime import datetime
from zoneinfo import ZoneInfo
dt = datetime(2025, 3, 21, 14, 35, 12, 123456, tzinfo=ZoneInfo("Europe/Moscow"))
print(dt.strftime("%Y-%m-%d %H:%M:%S")) # 2025-03-21 14:35:12
print(dt.strftime("%d.%m.%Y")) # 21.03.2025
print(dt.strftime("%H:%M")) # 14:35
print(dt.strftime("%Y-%m-%dT%H:%M:%S%z")) # 2025-03-21T14:35:12+0300
Совет: для обмена между сервисами используйте ISO 8601. Быстрый способ — dt.isoformat() или явный шаблон %Y-%m-%dT%H:%M:%S%z.
Парсинг строк в дату: strptime
strptime делает обратное: разбирает строку по формату в объект datetime. Следите, чтобы формат точно соответствовал строке.
from datetime import datetime
# 21.03.2025 14:35 → datetime (naive)
dt1 = datetime.strptime("21.03.2025 14:35", "%d.%m.%Y %H:%M")
# 2025-03-21T14:35:12+03:00 → datetime с tzinfo
dt2 = datetime.strptime("2025-03-21T14:35:12+03:00", "%Y-%m-%dT%H:%M:%S%z")
print(dt1, dt1.tzinfo) # None
print(dt2, dt2.tzinfo) # tzoffset +0300
# Частая ошибка: 12-часовой формат
# %H — 00..23, %I + %p — 01..12 c AM\/PM
dt3 = datetime.strptime("07:05 PM", "%I:%M %p")
print(dt3.strftime("%H:%M")) # 19:05
Совет: для ISO 8601 можно использовать datetime.fromisoformat — быстрее и без шаблонов, например datetime.fromisoformat("2025-03-21T14:35:12+03:00").
Таймзоны с zoneinfo: перевод и тонкости
Начиная с Python 3.9, используйте zoneinfo вместо внешних зависимостей. Всегда переводите локальное время в UTC перед хранением или сравнениями.
from datetime import datetime
from zoneinfo import ZoneInfo
msk = ZoneInfo("Europe/Moscow")
utc = ZoneInfo("UTC")
dt_msk = datetime(2025, 3, 21, 10, 0, tzinfo=msk)
dt_utc = dt_msk.astimezone(utc)
print(dt_msk, dt_utc)
# Присвоение tzinfo (без перевода) допустимо только если вы УЖЕ уверены,
# что naive datetime выражает локальное «настенное» время этой зоны.
naive_local = datetime(2025, 3, 21, 10, 0)
aware_local = naive_local.replace(tzinfo=msk)
# Теперь можно перевести в UTC:
print(aware_local.astimezone(utc))
Частые ловушки:
- Не смешивайте naive и aware в одном сравнении или арифметике.
- Не используйте tzinfo=timezone(offset) как «имя зоны» — это только фиксированное смещение без учёта переходов на летнее время.
- Для пользовательских интерфейсов храните в UTC, а показывайте в локальной зоне пользователя.
Арифметика времени: timedelta и «границы» суток
from datetime import datetime, timedelta
from zoneinfo import ZoneInfo
now = datetime.now(ZoneInfo("UTC"))
in_week = now + timedelta(days=7, hours=3)
print(in_week)
# Начало и конец дня (в конкретной зоне)
msk = ZoneInfo("Europe/Moscow")
dt = datetime(2025, 3, 21, 14, 35, tzinfo=msk)
start_of_day = dt.replace(hour=0, minute=0, second=0, microsecond=0)
end_of_day = start_of_day + timedelta(days=1) - timedelta(microseconds=1)
print(start_of_day, end_of_day)
Мини-практика: нормализация временных меток логов в UTC
Допустим, у нас логи с разными форматами времени. Задача — получить единый UTC для последующей аналитики.
from datetime import datetime
from zoneinfo import ZoneInfo
PATTERNS = [
"%Y-%m-%d %H:%M:%S,%f", # 2025-03-21 14:35:12,123
"%d/%m/%Y %H:%M:%S", # 21/03/2025 14:35:12
"%Y-%m-%dT%H:%M:%S%z", # 2025-03-21T14:35:12+03:00
]
DEFAULT_TZ = ZoneInfo("Europe/Moscow")
UTC = ZoneInfo("UTC")
def parse_to_utc(s: str) -> datetime:
# Сначала пробуем fromisoformat (быстро для ISO)
try:
dt = datetime.fromisoformat(s)
if dt.tzinfo is None:
dt = dt.replace(tzinfo=DEFAULT_TZ)
return dt.astimezone(UTC)
except Exception:
pass
# Затем проверяем набор известных форматов
for p in PATTERNS:
try:
dt = datetime.strptime(s, p)
if dt.tzinfo is None:
# Предполагаем, что строка — локальное время DEFAULT_TZ
dt = dt.replace(tzinfo=DEFAULT_TZ)
return dt.astimezone(UTC)
except Exception:
continue
raise ValueError(f"Не удалось разобрать дату: {s}")
lines = [
"2025-03-21 14:35:12,123 INFO User logged in",
"21/03/2025 11:35:12 WARN Disk space low",
"2025-03-21T14:35:12+03:00 ERROR Timeout",
]
for line in lines:
# Берём первые слова до пробела как дату (для примера)
ts = line.split(" ")[0]
try:
dt_utc = parse_to_utc(ts)
print(dt_utc.strftime("%Y-%m-%dT%H:%M:%S%z"), "→", line)
except ValueError as e:
print("SKIP:", e)
Идея: пытаться распарсить несколькими способами, аккуратно присваивать таймзону, затем переводить в UTC. В реальных задачах распознавайте временную метку регулярками и описывайте форматы явно.
Лучшие практики
- Храните время в UTC, показывайте пользователю в его зоне.
- Старайтесь работать только с aware datetime; избегайте смешивания с naive.
- Используйте ISO 8601 для API и интеграций (
isoformat()иfromisoformat()). - Для таймзон используйте
zoneinfo, а не «ручные» смещения. - При «приклеивании» таймзоны через
replace(tzinfo=...)будьте уверены, что время уже локальное для этой зоны.
Куда двигаться дальше
Хотите закрепить основы Python и уверенно применять их в проектах? Рекомендую Пройти курс «Python с Нуля до Гуру» и прокачать навыки на практике — там много упражнений, разборов и проектов для быстрого роста.
Освоив основы работы с датой и временем, вы избежите типичных багов и облегчите себе жизнь при интеграциях, аналитике и обработке событий во времени. Экспериментируйте с форматами, автоматизируйте конвертацию в UTC и держите под рукой zoneinfo — этого достаточно для большинства рабочих задач.
-
Создано 10.11.2025 17:01:36
-
Михаил Русаков

Комментарии (0):
Для добавления комментариев надо войти в систему.
Если Вы ещё не зарегистрированы на сайте, то сначала зарегистрируйтесь.