Даты и время в Python
См. также: Работа с типами · Анализ данных — pandas · Работа с файлами и API
Модуль datetime
Стандартный пакет datetime (не путать с именем типа) покрывает календарные даты, время суток, длительности и часовые пояса. Для логов, отчётов, API и аналитики это основной инструмент; в pandas временные ряды опираются на те же идеи — см. практикум по pandas.
Основные типы:
| Тип | Назначение |
|---|---|
date | Календарный день (год, месяц, день) |
time | Время суток без даты |
datetime | Дата + время |
timedelta | Разница двух моментов (дни, секунды, микросекунды) |
timezone | Смещение от UTC (фиксированное) |
Создание и "сейчас"
from datetime import date, datetime, time, timedelta
today = date.today()
now = datetime.now() # локальное время ОС, наивное
d = date(2026, 5, 25)
dt = datetime(2026, 5, 25, 14, 30, 0)
t = time(9, 0, 0)
Разбор примера:
- Импортируются четыре основных типа из модуля
datetime. date.today()возвращает только календарную дату без времени.datetime.now()возвращает текущие дату и время в локальной зоне ОС.date(...),datetime(...)иtime(...)создают значения с явно заданными компонентами.
datetime.now() и date.today() зависят от часового пояса системы. Для серверного кода предпочтительнее явная зона или UTC.
Наивные и осознанные (aware) объекты
Наивный datetime не содержит информации о поясе — только "стенные часы". Осознанный привязан к tzinfo (часто через zoneinfo в Python 3.9+).
from datetime import datetime, timezone
from zoneinfo import ZoneInfo
utc = datetime.now(timezone.utc)
moscow = datetime.now(ZoneInfo("Europe/Moscow"))
# перевод осознанного момента
moscow_from_utc = utc.astimezone(ZoneInfo("Europe/Moscow"))
Разбор примера:
timezone.utcзадаёт объект часового пояса UTC.ZoneInfo("Europe/Moscow")подключает региональную зону из базы IANA.datetime.now(...)в обоих случаях создаёт aware-объекты сtzinfo.astimezone(...)переводит один и тот же момент времени в другую зону.
Правило для backend и БД:
- хранить и передавать UTC (или Unix timestamp);
- переводить в локаль пользователя на границе (UI, отчёт);
- не сравнивать наивный и осознанный
datetime— будетTypeError.
# Ошибка — смешение наивного и aware
# naive < aware # TypeError
timedelta — арифметика длительностей
from datetime import datetime, timedelta
start = datetime(2026, 1, 1, 12, 0)
end = start + timedelta(days=7, hours=3)
delta = end - start
print(delta.days, delta.seconds) # целые дни и остаток секунд
Разбор примера:
timedelta(days=7, hours=3)описывает длительность 7 дней и 3 часов.- Операция
start + timedelta(...)сдвигает момент времени вперёд. - Разность
end - startвозвращает объектtimedelta. - Поля
daysиsecondsдают представление длительности в удобной форме.
timedelta не привязан к календарю: "+1 месяц" делают через dateutil.relativedelta (сторонняя библиотека) или логику pandas.
Форматирование и разбор строк
from datetime import datetime
dt = datetime(2026, 5, 25, 9, 5, 0)
text = dt.strftime("%Y-%m-%d %H:%M:%S") # "2026-05-25 09:05:00"
parsed = datetime.strptime("25.05.2026", "%d.%m.%Y")
Разбор примера:
strftime(...)форматирует объектdatetimeв строку по шаблону.%Y,%m,%dотвечают за год, месяц и день;%H,%M,%S— за время.strptime(...)выполняет обратную операцию: парсит строку по указанному формату.- Формат входной строки и шаблон должны совпадать буквально, иначе будет
ValueError.
| Код | Значение |
|---|---|
%Y | Год четырьмя цифрами |
%m | Месяц 01–12 |
%d | День |
%H | Час 00–23 |
%M | Минуты |
%S | Секунды |
Месяц, день и время с ведущим нулём. Для отдельных компонентов даты и времени в виде двухзначной строки в Python 3.x используют два стандартных подхода. Оба возвращают str.
Способ 1 — strftime() (специализирован для datetime):
from datetime import datetime
dt = datetime(2026, 1, 5, 9, 7)
month = dt.strftime("%m") # "01"
day = dt.strftime("%d") # "05"
clock = dt.strftime("%H:%M:%S") # "09:07:00"
Способ 2 — f-строки (прямой доступ к атрибутам):
month = f"{dt.month:02d}" # "01"
day = f"{dt.day:02d}" # "05"
clock = f"{dt.hour:02d}:{dt.minute:02d}:{dt.second:02d}" # "09:07:00"
# Аналог через format():
# month = "{:02d}".format(dt.month)
Составной вывод текущей даты и времени:
now = datetime.now()
print(f"{now.day:02d}.{now.month:02d}.{now.year}") # "05.01.2026"
print(f"{now.day:02d}.{now.month:02d}.{now.year} {now.hour:02d}:{now.minute:02d}") # "05.01.2026 09:07"
| Конструкция | Что возвращает | Тип | Примечание |
|---|---|---|---|
dt.strftime("%m") | Месяц 01–12 | str | Стандарт POSIX/Python |
dt.strftime("%d") | День 01–31 | str | Стандарт POSIX/Python |
dt.strftime("%H:%M:%S") | Время 00:00:00–23:59:59 | str | 24-часовой формат |
f"{dt.month:02d}" | Месяц 1–12 → 01–12 | str | Форматирование целых чисел |
f"{dt.day:02d}" | День 1–31 → 01–31 | str | Форматирование целых чисел |
f"{dt.hour:02d}" и т.д. | Час, минуты, секунды с нулём | str | Аналог %H, %M, %S |
Ведущий ноль сохраняется только в строковом представлении — при int("05") он исчезает, потому что целочисленный тип не хранит форматирование. Если нужен готовый составной формат (05.01.2026 или 05.01.2026 09:07), удобнее один вызов strftime: dt.strftime("%d.%m.%Y") или dt.strftime("%d.%m.%Y %H:%M"). Спецификаторы strftime регистрозависимы — %m это месяц, %M минуты; %d это день, %D дата в формате мм/дд/гг.
Для ISO 8601 удобнее методы экземпляра:
iso = dt.isoformat()
back = datetime.fromisoformat("2026-05-25T09:05:00+03:00")
Разбор примера:
isoformat()сериализует дату/время в стандарт ISO 8601.fromisoformat(...)восстанавливает объект из ISO-строки.- В примере
+03:00добавляет информацию о смещении, поэтому результат aware.
В JSON API даты обычно сериализуют в строку UTC (...Z) или Unix timestamp — см. примеры в главе про файлы и API.
Часовые пояса и переход на летнее время
Фиксированный timezone(timedelta(hours=3)) не учитывает DST (летнее время). Для реальных регионов используйте zoneinfo.ZoneInfo (база IANA в стандартной библиотеке с 3.9) или pytz в legacy-коде.
Типичная ошибка: "добавить 24 часа" вместо "следующий календарный день" в поясе с переводом стрелок — сдвиг на час. Для бизнес-дат (дедлайн "до конца 25 мая") часто достаточно типа date без времени.
Связь с pandas и БД
- pandas:
pd.to_datetime(), индексDatetimeIndex,dt.tz_localize/dt.tz_convert. - SQL: типы
TIMESTAMP WITH TIME ZONE/DATETIME— драйвер возвращаетdatetimeили строку; см. базы данных в Python. - Django:
USE_TZ = True, моделиDateTimeFieldхранят UTC в БД.
Практические рекомендации
- В логах — UTC + ISO формат.
- В тестах — фиксированные
datetime, неnow(), чтобы тесты были воспроизводимы. - Сравнение "событие раньше дедлайна" — приводить обе стороны к одной зоне или к UTC.
- Для только даты рождения / даты документа — тип
date, без времени и пояса.