Django-Admin.ru

datetime в Python: даты и время

Модуль datetime в Python: текущая дата и время, форматирование strftime и разбор strptime с таблицей кодов, timedelta, часовые пояса через zoneinfo.

Редакция Django-Admin.ru
· обновлено · 10 мин чтения

Содержание · 10 разделов
  1. Классы модуля datetime
  2. Текущая дата и время
  3. Как создать дату и получить её части
  4. strftime: дата в строку
  5. Таблица кодов strftime и strptime
  6. Названия месяцев по-русски
  7. strptime: строка в дату
  8. fromisoformat и isoformat
  9. timedelta: прибавить и вычесть время
  10. Часовые пояса: zoneinfo
  11. replace(tzinfo=) или astimezone()
  12. Переход на летнее время
  13. Unix timestamp
  14. Частые ошибки
  15. TypeError: can’t compare offset-naive and offset-aware datetimes
  16. ValueError: time data does not match format
  17. datetime.utcnow() устарел
  18. AttributeError: module ‘datetime’ has no attribute ‘now’
  19. Неверное использование .seconds
  20. Частые вопросы
  21. Как посчитать возраст по дате рождения?
  22. Как получить последний день месяца?
  23. Как вывести день и месяц без ведущего нуля?
  24. Как убрать микросекунды из datetime?
  25. Как узнать номер недели по ISO?
  26. Итог

Для дат и времени в 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фиксированное смещение от UTCtimezone.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–1210
%dдень месяца, 01–3109
%Hчас, 00–2314
%Iчас, 01–1202
%pAM/PM (зависит от локали)PM
%Mминуты, 00–5930
%Sсекунды, 00–5905
%fмикросекунды, 6 цифр123456
%Bполное название месяца (локаль)October
%bсокращённое название месяца (локаль)Oct
%Aполное название дня недели (локаль)Friday
%aсокращённое название дня неделиFri
%wдень недели, 0 — воскресенье5
%jномер дня в году, 001–366282
%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
  • #Стандартная библиотека
↑ ↓ выборEnter открытьEsc закрыть