Перейти к содержанию

412 уроков, 25 библиотек и челлендж «Что выведет код?» — бесплатно, код прямо в браузере

Начать обучение
Урок 6 из 20 Начальный 20 мин 120 XP

timedelta: разница между моментами

«Срок подписки истекает через 7 дней», «событие было 3 часа назад» — за этим стоит timedelta. Вычитаем моменты, читаем дни и секунды, прибавляем разницу к датам.

Редакция Питоники

До сих пор моменты из первых уроков стояли рядом и не взаимодействовали. Настоящая работа с датами начинается, когда их вычитают: сколько дней до дедлайна, сколько часов длился простой, какая дата будет через неделю. Python отвечает на все эти вопросы одним объектом — timedelta, разницей между моментами.

Разница — это объект timedelta

Из более позднего момента вычитаем более ранний — получаем timedelta. Создаётся он и руками: timedelta(days=7), timedelta(hours=5, minutes=30) — аргументы складываются в одну длительность. Импортируется из того же модуля: from datetime import datetime, timedelta.

разница двух моментов
from datetime import datetime, timedelta

start = datetime(2026, 10, 21, 12, 0)
end = datetime(2026, 10, 22, 15, 30)

delta = end - start
print(delta)
print(type(delta))
print(timedelta(hours=5))
Вывод
1 day, 3:30:00
<class 'datetime.timedelta'>
5:00:00

Печать timedelta читается слева направо: сначала дни, запятая, потом часы:минуты:секунды. 1 day, 3:30:00 — сутки и ещё три с половиной часа. Внутри объекта три главных поля: delta.days — количество полных суток; delta.seconds — это остаток внутри последних суток, а не всего секунд: для полного числа есть total_seconds(). И наконец delta.total_seconds() — вся длительность одним числом в секундах.

дни, остаток и всего разом
from datetime import datetime

start = datetime(2026, 10, 21, 12, 0)
end = datetime(2026, 10, 22, 15, 30)
delta = end - start

print(delta.days)
print(delta.seconds)
print(delta.total_seconds())
Вывод
1
12600
99000.0

Дата плюс timedelta — момент в будущем

смещаем момент
from datetime import datetime, timedelta

moment = datetime(2026, 10, 21, 12, 0)

print(moment + timedelta(days=7))
print(moment + timedelta(hours=5, minutes=30))
print(moment - timedelta(days=1))
Вывод
2026-10-28 12:00:00
2026-10-21 17:30:00
2026-10-20 12:00:00

Сложение сдвигает момент вперёд, вычитание — назад, и время внутри момента пересчитывается само: к полудню прибавили полсуток с получасом — получили 17:30 того же дня. Работает и с чистыми датами: date(2026, 10, 21) + timedelta(days=7) даст дату 2026-10-28 без времени — timedelta дружит со всеми классами из урока 2. Минус к разнице тоже применим: минус timedelta(days=1) — то же самое, что timedelta(days=-1), длительность бывает и отрицательной. Теперь соберём приём целиком: «сейчас» — подставная дата из урока 3, релиз — момент в будущем, а поле days разницы — готовый ответ на вопрос «сколько полных дней осталось».

дни до релиза
from datetime import datetime, timedelta

now = datetime(2026, 10, 23)          # подставное «сейчас»
release = datetime(2026, 11, 1, 12, 0)

left = release - now
print(left)
print(left.days)
print(now + timedelta(days=left.days))
Вывод
9 days, 12:00:00
9
2026-11-01 00:00:00

Обрати внимание на последнюю строку: к «сегодня» прибавили найденное число дней и получили полночь дня релиза. Так работают счётчики «осталось N дней» в интерфейсах: разница, поле days, при необходимости — обратное смещение для проверок. Возраст, стаж и рабочие дни строятся на том же приёме — им посвящены урок 16 и урок 17.

Отрицательная разница — это тоже разница

Пока разница была положительной, всё выглядело безобидно. Но дедлайны случаются и в прошлом: просроченный счёт, отменённый заказ, событие, которое началось раньше, чем закончилось. Вычитание в обратную сторону даёт timedelta с минусом, и вот тут начинается разница между «просто посмотреть» и «посчитать правильно». Поле days становится отрицательным, а вот total_seconds() честно отдаёт минус секунд — со знаком.

negative.py — разница в прошлом
from datetime import datetime

late = datetime(2026, 10, 24)
early = datetime(2026, 10, 21)

delta = early - late
print(delta)
print(delta.days)
print(delta.total_seconds())
Вывод
-3 days, 0:00:00
-3
-259200.0

Работать с таким знаком надо аккуратно, потому что timedelta хранит длительность в нормализованном виде: дни отдельно, остаток секунд отдельно, и остаток всегда неотрицательный. Для минус трёх дней это выглядит как days = -3, а не «-3 дня и минус 259200 секунд». Поэтому проверка «просрочено или нет» делается сравнением самих дат, а не знаком разницы: early < late читается прямо и не требует разбираться в нормализации.

36 часов — это 1 день и 12 часов

Ещё одно место, где datetime удивляет. Длительность нормализуется: сколько бы часов вы ни задали, timedelta хранит их как целые сутки плюс остаток. timedelta(hours=36) и timedelta(days=1.5) — это один и тот же объект, и оба печатаются как 1 day, 12:00:00. Дробные дни разрешены и равны часам ровно, потому что в сутках ровно 24 часа, а не 23 и не 25.

normalize.py — часы складываются в сутки
from datetime import timedelta

print(timedelta(hours=36))
print(timedelta(days=1.5))
print(timedelta(hours=2) * 3)
Вывод
1 day, 12:00:00
1 day, 12:00:00
6:00:00

Умножение и деление работают как с числами, и это иногда не то, что ожидаешь. Делить timedelta на timedelta можно, но получится обычное число — отношение двух длительностей, а не длительность. Деление timedelta на число даёт timedelta: шесть часов делённое на два — это три часа.

divide.py — доли и части
from datetime import timedelta

work = timedelta(hours=6)
total = timedelta(hours=10)

print(round(work / total * 100))
print(total - work)
print(round(total.total_seconds() / 3600, 1))
Вывод
60
4:00:00
10.0

Полные сутки против календарных

Поле days отвечает на вопрос «сколько полных суток прошло», и это не то же самое, что «сколько суток от дедлайна». Между ними может быть полсуток. Если до дедлайна осталось 30 часов, days покажет 1, а по календарю это полтора дня. Для счётчика «осталось N дней» в интерфейсе обычно нужен второй вариант — округление вверх: осталось 2 дня, потому что 30 часов это больше суток. Считать надо явно, а не полагаться на то, что поле days даст «правильное» число.

partial.py — неполные сутки
from datetime import timedelta

delta = timedelta(hours=30)

print(delta)
print(delta.days)
print(round(delta.total_seconds() / 86400, 2))
Вывод
1 day, 6:00:00
1
1.25

Кстати, делить на 86400 — число секунд в сутках — приходится постоянно, и это нормально. Отдельного метода «сколько суток дробью» у timedelta нет, а total_seconds() даёт секунды, из которых сутки приходится вычислять. Мы держим в проектах константу SECONDS_PER_DAY = 86400, чтобы магическое число не встречалось в коде вперемешку с календарными датами.

timedelta в счёте: дни, минуты и граница месяца

timedelta умеет всё, что связано с интервалами: складываться, вычитаться, умножаться на число, делиться на другое timedelta. Но у него есть одно свойство, о котором стоит знать заранее: он хранит дни, секунды и микросекунды, а месяцев и годов в нём нет.

Поэтому timedelta(days=30) — это 30 дней, а не месяц. Для примера «дедлайн через месяц» это даст другую дату, чем «через 30 дней»: 15 марта плюс месяц — это 15 апреля, а плюс 30 дней — 14 апреля, потому что в марте 31 день. Разница в один-три дня, и именно на таких расчётах забывают про платежи.

Практическое правило: если в задаче фигурирует календарный период (месяц, квартал, год), считайте через границы периода — первый день месяца и первый день следующего, — а не через timedelta с числом дней. Отдельный модуль calendar подсказывает, сколько дней в конкретном месяце, и про него отдельный урок 15. Если же речь о точной длительности (смена длится 12 часов, дедлайн через 3 дня) — timedelta идеален.

И ещё полезная деталь, на которой мы спотыкались: делить timedelta на timedelta можно, но обычное деление даёт дробь, а целочисленное — число полных единиц. delta / timedelta(minutes=1) вернёт 330.0, а delta // timedelta(minutes=1) — 330. Второе и нужно для отчёта «сколько полных минут заняла обработка»: первое округлит 330.5 минут до 330.5 и потеряет половину минуты.

minutes.py — целые минуты и дробная часть
from datetime import timedelta

delta = timedelta(hours=5, minutes=31)

print(delta // timedelta(minutes=1))
print(delta / timedelta(minutes=1))
print(delta // timedelta(hours=1))
Вывод
331
331.0
5
Что выведет код?

Сначала предскажи ответ в голове — это главный навык программиста.

from datetime import datetime

start = datetime(2026, 10, 21, 12, 0)
end = datetime(2026, 10, 22, 15, 30)

print((end - start).days)
from datetime import datetime, timedelta

moment = datetime(2026, 10, 21, 12, 0)
print(moment + timedelta(days=7))
from datetime import datetime

now = datetime(2026, 10, 23)
release = datetime(2026, 11, 1, 12, 0)

left = release - now
print(left)
from datetime import datetime, timedelta

now = datetime(2026, 10, 21)
release = datetime(2026, 11, 1, 12, 0)

left = release - now
print(left.days)
print(round(left.total_seconds() / 86400, 2))
Проверь себя
0 / 8

1. Что вернёт выражение datetime(2026, 11, 1) - datetime(2026, 10, 21)?

2. Что означает поле delta.seconds у timedelta(days=2, hours=3)?

3. Как получить всю длительность timedelta одним числом?

4. Что получится, если к datetime прибавить timedelta(days=7)?

5. Какая длительность у timedelta(hours=5, minutes=30)?

6. Что вернёт timedelta(hours=36)?

7. Что вернёт выражение timedelta(hours=6) / timedelta(hours=10)?

8. У timedelta(hours=30) какое значение поля days?

Карточки терминов
Запомнено: 0 / 9
Практика

Тренировка началась в 21 октября 2026 года в 19:00 и закончилась в тот же день в 21:30. Выведи длительность, общее число секунд длительности и момент следующей тренировки — ровно через 3 дня после первой.

practice.py
Вопросы и ответы по уроку

Как посчитать разницу между двумя датами в Python?

Просто вычесть: d2 - d1 вернёт объект timedelta. Поле .days даст полные сутки разницы, total_seconds() — всю длительность в секундах. Для дат без времени разница всегда целодневная: date(2026, 11, 1) - date(2026, 10, 21) — это 11 days, 0:00:00.

Урок 6: timedelta

Почему delta.seconds показывает не все секунды?

Потому что timedelta хранится как комбинация дней и остатка: days — полные сутки, seconds — остаток от 0 до 86399 внутри последних суток. Вся длительность одним числом — только total_seconds(). Для timedelta(days=2, hours=3) поле seconds — 10800, а total_seconds() — 183600.0.

Как прибавить к дате несколько дней?

Создать timedelta и сложить: moment + timedelta(days=7) — момент на неделю позже. Работает с датами, временем, днями, часами, минутами и секундами одновременно: timedelta(days=1, hours=6, minutes=30).

Может ли timedelta быть отрицательным?

Да: вычитание более позднего момента из более раннего даст отрицательную длительность, например timedelta(days=-1). Поле days при этом отрицательное, а seconds остаётся неотрицательным хвостом; для «просрочено или нет» проще сравнивать сами даты — об этом урок 7.

Урок 7: сравнение дат

Как посчитать процент выполненной работы через timedelta?

Разделить одну длительность на другую и умножить на 100: round(work / total * 100). Деление timedelta на timedelta даёт обычное число, а не длительность. Round нужен обязательно: без него получится 59.99999999999999 из-за двоичной точности.

Почему timedelta(hours=36) печатается как 1 day, 12:00:00?

Длительность всегда нормализуется: целые сутки плюс остаток. Поэтому timedelta(hours=36) и timedelta(days=1.5) — один и тот же объект, и любые timedelta с тем же количеством секунд сравниваются между собой как равные.

Что означает отрицательный timedelta?

Что разница посчитана в обратную сторону: более ранний момент минус более поздний. Поле days при этом отрицательное, а остаток секунд — неотрицательный, потому что timedelta хранит длительность в нормализованном виде. Чтобы проверить «просрочено ли», сравнивайте сами даты: это читается прямо.

Понравился урок? Сошлитесь на него

«delta.seconds — это остаток внутри последних суток, а не всего секунд: для полного числа есть total_seconds().»

Скопируйте готовую ссылку в формате HTML, Markdown или чистый адрес и вставьте в статью на Habr, VC, Telegram-канал или свой блог — так о проекте узнают новые читатели.

TelegramVK

Что дальше

Осталось в разделе: 20 из 20. Прогресс хранится в вашем браузере.

Похожие уроки по темам

Подобраны автоматически по пересечению тем и ключевых слов.