datetime в Python: даты и время
Модуль datetime в Python: текущая дата и время, форматирование strftime и разбор strptime с таблицей кодов, timedelta, часовые пояса через zoneinfo.
Содержание · 10 разделов
- Классы модуля datetime
- Текущая дата и время
- Как создать дату и получить её части
- strftime: дата в строку
- Таблица кодов strftime и strptime
- Названия месяцев по-русски
- strptime: строка в дату
- fromisoformat и isoformat
- timedelta: прибавить и вычесть время
- Часовые пояса: zoneinfo
- replace(tzinfo=) или astimezone()
- Переход на летнее время
- Unix timestamp
- Частые ошибки
- TypeError: can’t compare offset-naive and offset-aware datetimes
- ValueError: time data does not match format
- datetime.utcnow() устарел
- AttributeError: module ‘datetime’ has no attribute ‘now’
- Неверное использование .seconds
- Частые вопросы
- Как посчитать возраст по дате рождения?
- Как получить последний день месяца?
- Как вывести день и месяц без ведущего нуля?
- Как убрать микросекунды из datetime?
- Как узнать номер недели по ISO?
- Итог
Для дат и времени в Python есть стандартный модуль datetime. Короткий ответ: datetime.now() возвращает текущие дату и время, dt.strftime("%d.%m.%Y") превращает дату в строку, datetime.strptime(text, "%d.%m.%Y") — строку в дату, а timedelta(days=7) позволяет прибавлять и вычитать интервалы. Для часовых поясов используйте zoneinfo.ZoneInfo("Europe/Moscow").
Ниже разберём классы модуля, форматирование и разбор строк с полной таблицей кодов, арифметику дат, часовые пояса и типичные ошибки. Примеры проверены на Python 3.12, вывод показан комментарием # →.
Классы модуля datetime
| Класс | Что хранит | Пример |
|---|---|---|
date | дату: год, месяц, день | date(2026, 10, 9) |
time | время суток без даты | time(14, 30) |
datetime | дату и время вместе | datetime(2026, 10, 9, 14, 30) |
timedelta | интервал: дни, секунды, микросекунды | timedelta(days=7) |
timezone | фиксированное смещение от UTC | timezone.utc |
Модуль и главный класс называются одинаково. Поэтому обычно пишут from datetime import datetime, а не import datetime — иначе придётся обращаться как datetime.datetime.now().
Текущая дата и время
from datetime import date, datetime
now = datetime.now()
print(now) # → 2026-10-09 15:00:44.294706 (у вас — текущий момент)
print(date.today()) # → 2026-10-09
datetime.now() без аргументов возвращает наивное время — местное время компьютера без информации о часовом поясе. Для серверного кода почти всегда нужен вариант с поясом, например datetime.now(timezone.utc) (см. раздел о часовых поясах).
Как создать дату и получить её части
from datetime import date, datetime, time
dt = datetime(2026, 10, 9, 14, 30)
print(dt) # → 2026-10-09 14:30:00
print(dt.year, dt.month, dt.day) # → 2026 10 9
print(dt.hour, dt.minute, dt.second) # → 14 30 0
print(dt.weekday(), dt.isoweekday()) # → 4 5 (пятница)
print(dt.date(), dt.time()) # → 2026-10-09 14:30:00
print(dt.replace(hour=0, minute=0)) # → 2026-10-09 00:00:00
print(datetime.combine(date(2026, 10, 9), time(9, 0))) # → 2026-10-09 09:00:00
weekday() считает понедельник за 0, а isoweekday() — за 1. Объекты datetime неизменяемы: replace() возвращает новый объект и не меняет исходный.
strftime: дата в строку
Метод strftime() форматирует дату по шаблону из кодов с символом %:
dt = datetime(2026, 10, 9, 14, 30, 5)
print(dt.strftime("%d.%m.%Y %H:%M")) # → 09.10.2026 14:30
print(dt.strftime("%Y-%m-%d")) # → 2026-10-09
print(dt.strftime("%d %B %Y, %A")) # → 09 October 2026, Friday
print(f"{dt:%d.%m.%Y}") # → 09.10.2026 — то же в f-строке
Формат прямо в f-строке после двоеточия работает так же, как strftime(). Подробнее о форматировании — в статье про f-строки.
Таблица кодов strftime и strptime
Значения в таблице — для datetime(2026, 10, 9, 14, 30, 5, 123456):
| Код | Значение | Пример |
|---|---|---|
%Y | год, 4 цифры | 2026 |
%y | год, 2 цифры | 26 |
%m | месяц, 01–12 | 10 |
%d | день месяца, 01–31 | 09 |
%H | час, 00–23 | 14 |
%I | час, 01–12 | 02 |
%p | AM/PM (зависит от локали) | PM |
%M | минуты, 00–59 | 30 |
%S | секунды, 00–59 | 05 |
%f | микросекунды, 6 цифр | 123456 |
%B | полное название месяца (локаль) | October |
%b | сокращённое название месяца (локаль) | Oct |
%A | полное название дня недели (локаль) | Friday |
%a | сокращённое название дня недели | Fri |
%w | день недели, 0 — воскресенье | 5 |
%j | номер дня в году, 001–366 | 282 |
%W | номер недели, неделя с понедельника | 40 |
%z | смещение от UTC (у aware-даты) | +0300 |
%Z | имя часового пояса (у aware-даты) | MSK |
%% | символ % | % |
У наивной даты %z и %Z дают пустую строку. Полный список кодов — в документации модуля datetime.
Названия месяцев по-русски
%B и %A выводят названия на языке текущей локали — по умолчанию английском. Переключение через locale.setlocale() зависит от операционной системы и меняет состояние всей программы, а в именительном падеже «октябрь» в дате всё равно звучит неестественно. Надёжнее держать свой список:
MONTHS = ["января", "февраля", "марта", "апреля", "мая", "июня",
"июля", "августа", "сентября", "октября", "ноября", "декабря"]
dt = datetime(2026, 10, 9)
print(f"{dt.day} {MONTHS[dt.month - 1]} {dt.year} г.") # → 9 октября 2026 г.
strptime: строка в дату
datetime.strptime() разбирает строку по тем же кодам. Шаблон должен точно совпадать с форматом строки:
p = datetime.strptime("09.10.2026 14:30", "%d.%m.%Y %H:%M")
print(repr(p)) # → datetime.datetime(2026, 10, 9, 14, 30)
print(datetime.strptime("2026-10-09", "%Y-%m-%d").date()) # → 2026-10-09
Если строка не подходит под шаблон или дата не существует, будет ValueError:
datetime.strptime("2026-10-09", "%d.%m.%Y")
# → ValueError: time data '2026-10-09' does not match format '%d.%m.%Y'
datetime.strptime("31.02.2026", "%d.%m.%Y")
# → ValueError: day is out of range for month
В Python 3.14 текст второй ошибки подробнее: day 31 must be in range 1..28 for month 2 in year 2026.
fromisoformat и isoformat
Для формата ISO 8601 (2026-10-09T14:30:00) шаблон не нужен. isoformat() выводит дату в этом формате, а fromisoformat() разбирает её; с Python 3.11 он понимает и суффикс Z:
print(datetime(2026, 10, 9, 14, 30).isoformat()) # → 2026-10-09T14:30:00
print(repr(datetime.fromisoformat("2026-10-09T11:30:00Z")))
# → datetime.datetime(2026, 10, 9, 11, 30, tzinfo=datetime.timezone.utc)
ISO 8601 — лучший формат для хранения дат в файлах и API, в том числе в JSON. Как сериализовать datetime в JSON и прочитать обратно, рассказано в статье о модуле json.
timedelta: прибавить и вычесть время
timedelta описывает интервал. Его прибавляют к дате, а разность двух дат возвращает timedelta:
from datetime import date, datetime, timedelta
dt = datetime(2026, 10, 9, 14, 30)
print(dt + timedelta(days=7)) # → 2026-10-16 14:30:00
print(dt - timedelta(hours=36)) # → 2026-10-08 02:30:00
print(dt + timedelta(weeks=2, minutes=15)) # → 2026-10-23 14:45:00
left = date(2026, 12, 31) - date(2026, 10, 9)
print(left, left.days) # → 83 days, 0:00:00 83
work = datetime(2026, 10, 9, 18, 45) - datetime(2026, 10, 9, 9, 0)
print(work) # → 9:45:00
print(work.total_seconds() / 3600) # → 9.75
Внутри timedelta хранит только дни, секунды и микросекунды: атрибут .seconds — это остаток без учёта дней. Для полной длительности используйте total_seconds():
d = timedelta(days=1, hours=2, minutes=30)
print(d.days, d.seconds, d.total_seconds()) # → 1 9000 95400.0
Месяцев и лет в timedelta нет, потому что они разной длины: timedelta(months=1) выбросит TypeError. Для календарной арифметики («тот же день следующего месяца») используют relativedelta из сторонней библиотеки python-dateutil или считают вручную через replace().
Даты одного вида можно сравнивать и сортировать обычными операторами: date(2026, 10, 9) > date(2026, 1, 1) вернёт True.
Часовые пояса: zoneinfo
Объект datetime бывает двух видов:
- наивный (naive) — без часового пояса,
tzinfoравенNone; - осведомлённый (aware) — с часовым поясом, однозначно указывает момент времени.
С Python 3.9 часовые пояса из базы IANA подключаются стандартным модулем zoneinfo:
from datetime import datetime, timezone
from zoneinfo import ZoneInfo
msk = ZoneInfo("Europe/Moscow")
meeting = datetime(2026, 10, 9, 14, 30, tzinfo=msk)
print(meeting) # → 2026-10-09 14:30:00+03:00
print(meeting.utcoffset()) # → 3:00:00
print(meeting.astimezone(ZoneInfo("Asia/Vladivostok"))) # → 2026-10-09 21:30:00+10:00
print(meeting.astimezone(ZoneInfo("Europe/Berlin"))) # → 2026-10-09 13:30:00+02:00
print(meeting.astimezone(timezone.utc)) # → 2026-10-09 11:30:00+00:00
print(meeting.strftime("%d.%m.%Y %H:%M %Z (%z)")) # → 09.10.2026 14:30 MSK (+0300)
astimezone() пересчитывает тот же момент в другой пояс. Текущее время в UTC возвращает datetime.now(timezone.utc).
Важно: на Windows в системе нет базы часовых поясов IANA, и
ZoneInfo("Europe/Moscow")выброситZoneInfoNotFoundError: 'No time zone found with key Europe/Moscow'. Установите пакет с базой:pip install tzdata. На Linux и macOS база обычно уже есть.
replace(tzinfo=) или astimezone()
replace(tzinfo=...) приписывает пояс, не меняя часы. astimezone() пересчитывает время в новый пояс:
naive = datetime(2026, 10, 9, 14, 30)
print(naive.replace(tzinfo=msk)) # → 2026-10-09 14:30:00+03:00 — те же 14:30, но в Москве
# 14:30 по UTC — это 17:30 по Москве
print(naive.replace(tzinfo=timezone.utc).astimezone(msk)) # → 2026-10-09 17:30:00+03:00
Практическое правило: храните и сравнивайте время в UTC, а в местный пояс переводите только для показа пользователю. Так же устроен Django при USE_TZ = True.
Переход на летнее время
ZoneInfo учитывает летнее время. При сложении с timedelta сохраняются «настенные» часы, а смещение пересчитывается:
ber = ZoneInfo("Europe/Berlin")
x = datetime(2026, 3, 28, 12, 0, tzinfo=ber)
print(x) # → 2026-03-28 12:00:00+01:00
print(x + timedelta(days=1)) # → 2026-03-29 12:00:00+02:00
Между этими моментами прошло 23 часа, а не 24. Если нужна точная длительность, выполняйте арифметику в UTC.
Unix timestamp
ts = meeting.timestamp()
print(ts) # → 1791545400.0
print(datetime.fromtimestamp(ts, tz=timezone.utc)) # → 2026-10-09 11:30:00+00:00
Без аргумента tz метод fromtimestamp() вернёт наивное местное время компьютера.
Частые ошибки
TypeError: can’t compare offset-naive and offset-aware datetimes
Сравнивать или вычитать наивную и aware-дату нельзя:
naive < meeting # → TypeError: can't compare offset-naive and offset-aware datetimes
meeting - naive # → TypeError: can't subtract offset-naive and offset-aware datetimes
Приведите обе даты к одному виду: добавьте пояс через replace(tzinfo=...), если точно знаете, в каком поясе записано наивное время.
ValueError: time data does not match format
Шаблон strptime() не совпадает со строкой: другой разделитель, лишний пробел, двухзначный год вместо четырёхзначного (%y против %Y). Сравните строку и шаблон посимвольно.
datetime.utcnow() устарел
С Python 3.12 datetime.utcnow() и datetime.utcfromtimestamp() объявлены устаревшими и выдают DeprecationWarning. Они возвращают наивное время, которое легко принять за местное. Используйте datetime.now(timezone.utc) и datetime.fromtimestamp(ts, tz=timezone.utc).
AttributeError: module ‘datetime’ has no attribute ‘now’
Вы написали import datetime, а вызываете datetime.now(). Либо импортируйте класс — from datetime import datetime, — либо обращайтесь полностью: datetime.datetime.now().
Неверное использование .seconds
timedelta(days=2).seconds равно 0, потому что .seconds не включает дни. Для общей длительности нужен total_seconds().
Частые вопросы
Как посчитать возраст по дате рождения?
Вычтите годы и отнимите единицу, если день рождения в этом году ещё не наступил. Сравнение кортежей (месяц, день) делает это в одну строку:
from datetime import date
def age(birth, today):
return today.year - birth.year - ((today.month, today.day) < (birth.month, birth.day))
print(age(date(1995, 10, 10), date(2026, 10, 9))) # → 30
print(age(date(1995, 10, 9), date(2026, 10, 9))) # → 31
Деление (today - birth).days / 365 даёт ошибку на границе из-за високосных лет.
Как получить последний день месяца?
calendar.monthrange(год, месяц) возвращает день недели первого числа и количество дней в месяце — второе значение и есть последний день:
import calendar
from datetime import date
last = calendar.monthrange(2026, 2)[1]
print(date(2026, 2, last)) # → 2026-02-28
Как вывести день и месяц без ведущего нуля?
Коды %-d (Linux, macOS) и %#d (Windows) зависят от платформы, поэтому надёжнее собрать строку из атрибутов:
dt = datetime(2026, 10, 9, 14, 30)
print(f"{dt.day}.{dt.month}.{dt.year}") # → 9.10.2026
Как убрать микросекунды из datetime?
Для объекта — replace(microsecond=0), для строки ISO — параметр timespec:
now = datetime(2026, 10, 9, 15, 0, 44, 294706)
print(now.replace(microsecond=0)) # → 2026-10-09 15:00:44
print(now.isoformat(timespec="seconds")) # → 2026-10-09T15:00:44
Как узнать номер недели по ISO?
isocalendar() возвращает год, номер недели и день недели по ISO 8601, где неделя начинается с понедельника, а первая неделя года содержит первый четверг:
print(date(2026, 10, 9).isocalendar().week) # → 41
Код %W из таблицы выше считает недели иначе (неделя 0 — дни до первого понедельника года), поэтому для того же дня даёт 40. В strftime() ISO-номеру соответствует код %V.
Итог
Для большинства задач хватает четырёх инструментов: datetime.now(timezone.utc) для текущего момента, strftime() и strptime() для перевода в строку и обратно, timedelta для арифметики и ZoneInfo для часовых поясов. Храните время в UTC, а для обмена данными используйте ISO 8601. Остальные модули стандартной библиотеки и конструкции языка — в шпаргалке по синтаксису Python, а ошибки вроде TypeError и ValueError удобно перехватывать через try/except.
- #Python
- #datetime
- #Дата и время
- #zoneinfo
- #Стандартная библиотека