Понимание времени в Python: полное руководство по datetime
Серия 03 – операции с датой/временем, часовые пояса, преобразование форматов
Время – это не просто строка. Дни сменяются, месяцы переходят, летнее время вступает в силу, а в разных регионах правила различаются. Поэтому при работе с датой и временем важно различать «отображаемую строку» и «числовое значение», а также учитывать часовые пояса.

В этой статье мы сосредоточимся на модуле datetime и разберём:
- Создание текущего времени и даты
- Вычисление периодов (
timedelta) - Форматирование и разбор строк (
strftime,strptime) - Работа с часовыми поясами (
timezone,zoneinfo) - Частые ошибки и надёжные шаблоны
1. Что предоставляет datetime?
В datetime есть несколько типов, которые выглядят похожими, но выполняют разные задачи.
date– только год‑месяц‑деньtime– только часы‑минуты‑секундыdatetime– дата и время (самый распространённый тип)timedelta– разница во времени (период)timezone– фиксированный смещение часового пояса (например, UTC+9)
Начиная с Python 3.9 в стандартную библиотеку вошёл модуль zoneinfo, упрощающий работу с региональными часовыми поясами (например, Asia/Tokyo).
2. Как получить «сейчас»: naive vs aware
2.1 Что такое naive и aware?
Объекты datetime делятся на две категории.
- naive datetime – без информации о часовом поясе
- aware datetime – с информацией о часовом поясе (
tzinfo)
Смешивание этих типов при вычислениях может привести к ошибкам или неожиданным результатам.
2.2 Рекомендуемое значение по умолчанию: начать с UTC aware
Единый стандарт UTC упрощает хранение и расчёты.
from datetime import datetime, timezone
utc_now = datetime.now(timezone.utc) # aware (UTC)
print(utc_now)
Если нужна локальная дата, преобразуем на этапе отображения.
from datetime import datetime, timezone
from zoneinfo import ZoneInfo
utc_now = datetime.now(timezone.utc)
tokyo_now = utc_now.astimezone(ZoneInfo("Asia/Tokyo"))
print(utc_now)
print(tokyo_now)
3. Вычисления даты/времени: timedelta в центре внимания
3.1 Сложение/вычитание
from datetime import datetime, timedelta, timezone
now = datetime.now(timezone.utc)
print(now + timedelta(days=3))
print(now - timedelta(hours=2))
3.2 Разница между двумя моментами
from datetime import datetime, timezone
a = datetime(2026, 1, 1, tzinfo=timezone.utc)
b = datetime(2026, 1, 10, tzinfo=timezone.utc)
delta = b - a
print(delta.days) # 9
print(delta.total_seconds()) # 777600.0
3.3 Как воспринимать «период» через timedelta
timedelta работает в днях, секундах и микросекундах. Выражения вроде «через месяц» требуют более сложных подходов (например, dateutil), поскольку длина месяца меняется.
4. Форматирование и разбор: strftime / strptime
4.1 datetime → строка (strftime)
from datetime import datetime, timezone
dt = datetime(2026, 1, 30, 14, 5, 0, tzinfo=timezone.utc)
print(dt.strftime("%Y-%m-%d %H:%M:%S %z"))
Часто используемые шаблоны:
%Y-%m-%d– 2026-01-30%H:%M:%S– 14:05:00%z– +0000 (смещение UTC)
4.2 строка → datetime (strptime)
from datetime import datetime
s = "2026-01-30 14:05:00"
dt = datetime.strptime(s, "%Y-%m-%d %H:%M:%S")
print(dt)
Полученный dt – naive. Чтобы задать часовой пояс, добавляем tzinfo.
from datetime import datetime, timezone
s = "2026-01-30 14:05:00"
dt = datetime.strptime(s, "%Y-%m-%d %H:%M:%S").replace(tzinfo=timezone.utc)
print(dt)
replace(tzinfo=...)не меняет время, а только присваивает метку часового пояса. Для реального преобразования используйтеastimezone().
5. Часовые пояса: различие между timezone и zoneinfo
5.1 Фиксированное смещение – timezone
from datetime import datetime, timezone, timedelta
kst_fixed = timezone(timedelta(hours=9))
dt = datetime(2026, 1, 30, 12, 0, tzinfo=kst_fixed)
print(dt)
5.2 Региональный часовой пояс – zoneinfo
Для зон с летним временем используйте zoneinfo.
from datetime import datetime, timezone
from zoneinfo import ZoneInfo
utc_now = datetime.now(timezone.utc)
ny_now = utc_now.astimezone(ZoneInfo("America/New_York"))
print(ny_now)
5.3 replace(tzinfo=...) vs astimezone(...)
replace(tzinfo=...)– время остаётся тем же, меняется только меткаastimezone(...)– переводит момент во времени в другой часовой пояс
Понимание разницы помогает избежать багов.
6. Частые ошибки
6.1 Смешивание naive/aware
- Для внутренних расчётов лучше использовать aware (UTC)
- При вводе данных сразу определяйте и нормализуйте часовой пояс
6.2 «Локальное время» может отличаться в разных средах
datetime.now() использует локальные настройки среды. В контейнерах это может быть UTC. Лучше явно указывать datetime.now(timezone.utc).
6.3 Несоответствие формата при разборе строк
strptime чувствителен к формату: даже один символ разницы приводит к ошибке. Если входные строки могут иметь разные форматы, предварительно нормализуйте их или пробуйте несколько шаблонов.
7. Три популярных шаблона
7.1 Сохранение в формате ISO 8601
from datetime import datetime, timezone
dt = datetime.now(timezone.utc)
print(dt.isoformat()) # пример: 2026-01-30T05:12:34.567890+00:00
7.2 Формирование имени файла с сегодняшней датой
from datetime import datetime
stamp = datetime.now().strftime("%Y%m%d")
filename = f"report_{stamp}.json"
print(filename)
7.3 Вычисление оставшегося времени до заданного момента
from datetime import datetime, timezone
target = datetime(2026, 2, 1, 0, 0, tzinfo=timezone.utc)
now = datetime.now(timezone.utc)
remaining = target - now
print(remaining)
print(remaining.total_seconds())
8. Итоги
Модуль datetime позволяет не только форматировать даты, но и выполнять надёжные расчёты времени. Включение часовых поясов (timezone, zoneinfo) делает код устойчивым к различиям среды.
В следующей статье мы разберём модуль random, включая генерацию случайных чисел, выборки, перемешивание и безопасные случайные значения (secrets).
Связанные статьи:
- Правильное использование datetime и timezone в Django
- Чудо управления временем в Django - Полное руководство по 'django.utils.timezone'
Предыдущие части серии
Комментариев нет.