Арифметика дат. Класс timedelta

Курс по стандартной библиотеке: https://stepik.org/a/259466?utm_source=proproprogs

Смотреть материал на YouTube | RuTube

Продолжаем рассматривать основные принципы работы объектов класса datetime.date. На этом занятии увидим, как с его помощью можно выполнять различные арифметические вычисления с датами.

Пусть, например, имеются два объекта для текущего и предыдущего дней:

today = datetime.date.today()
yesterday = today.replace(day=today.day-1)

Тогда на их основе можно вычислить разницу между сегодняшним и вчерашним днем:

delta = today - yesterday
print(delta)  # 1 day, 0:00:00

Полученный результат (один день) будет сохранен в объекте delta типа timedelta. Объекты этого класса часто используются в операциях с календарными датами. Например, мы бы хотели создать объект  yesterday путем вычитания одного дня из объекта today:

yesterday = today - 1  # ошибка

Но такая операция приведет к ошибке, т.к. арифметические операции с обычными целочисленными значениями недопустимы. Это связано с тем, что непонятно как интерпретировать число 1: как день, или как год, или как месяц или что-то еще. Поэтому разработчики модуля добавили еще один класс timedelta, с которым можно выполнять подобные вычисления с датами:

yesterday = today - datetime.timedelta(days=1)

Вообще объекты класса datetime.timedelta описывают именно интервалы времени, то есть разницы между двумя моментами времени. Интервал может выражаться в неделях, днях, секундах и микросекундах. Поэтому объекты этого класса конструируются согласно синтаксису:

timedelta([days[, seconds[, microseconds[, milliseconds[, minutes[, hours[, weeks]]]]]])

Например:

zero = timedelta()  # нулевой интервал
one_day = timedelta(days=1)
one_week = timedelta(weeks=1)
last_week = timedelta(weeks=-1)
two_last_hours = timedelta(hours=-2)
dt = timedelta(days=5, hours=6, milliseconds=10)

Как видите, интервалы могут содержать отрицательные значения. И обратите внимание на разницу определения следующих объектов:

one_day = timedelta(days=1)  # один день
first_day = datetime.date(year=1, day=1, month=1)  # дата: 0001-01-01

Поэтому когда нам нужен именно временной интервал, то удобно использовать объекты класса timedelta.

Объекты класса timedelta содержат следующие полезные свойства, доступные только для чтения:

days = one_week.days  # 7
seconds = one_week.seconds  # 0
microseconds = one_week.microseconds  # 0

Обратите внимание, что свойств weeks, months и подобных не существует, только дни, секунды и микросекунды. Причем все эти три свойства работают в сочетании друг с другом. Поэтому для одной недели будет 7 дней и 0 секунд. А вот, например, для такого интервала:

td = timedelta(weeks=1, hours=12)

получим:

days = td.days  # 7
seconds = td.seconds  # 43200
microseconds = td.microseconds  # 0

Если же нам нужно узнать общее число секунд в заданном интервале, то можно воспользоваться методом total_seconds():

sc = td.total_seconds()  # 648000.0

Арифметика с интервалами и датами

На основе существующих интервалов мы можем создавать новые путем выполнения арифметических операций с ними. Например, на основе интервала one_day можно сформировать еще несколько следующим образом:

twodays = 2 * one_day
half_day = one_day / 2
three_days = one_day + two_days
one_and_half_day = one_day * 1.5

Обратите внимание, что объекты класса date можно только вычитать между собой:

today = datetime.date.today()
yesterday = today - one_day
t = today - yesterday

вычисляя временные интервалы в виде объектов класса timedelta. А вот с объектами timedelta можно выполнять операции и вычитания и сложения. Пусть, например, у нас заданы интервалы в один день и одну неделю, а также дата в виде текущего дня:

one_day = timedelta(days=1)
one_week = timedelta(weeks=1)
today = datetime.date.today()

На их основе достаточно просто можно вычислить следующие даты:

yesterday = today - one_day
tomorrow = today + one_day
last_week = today - one_week
next_week = today + one_week

Видите, как это удобно и наглядно записано в тексте программы. Каждый программист легко поймет, что здесь вычисляется.

Конечно, другие арифметические операции с объектами date и timedelta выполнять нельзя, только складывать и вычитать. Например, следующие команды приведут к ошибкам:

t = today * one_day
t = today / one_day

Сравнение интервалов и дат

С объектами классов date и timedelta можно выполнять операции сравнения. Например, такие:

one_day < one_week  # True
one_day == one_week  # False
today <= yesterday  # False
today > yesterday  # True
last_week != next_week  # True

То есть, здесь можно использовать все стандартные операции сравнения. Но только с объектами одного и того же типа. Например, следующие команды приведут к ошибкам:

today < one_day  # TypeError
one_week >= next_week  # TypeError

Хотя операции сравнения на равенство и неравенство, формально, сработают:

one_week == next_week  # False

но в них нет особого смысла, т.к. интервалы времени и конкретная дата – разные сущности.

В заключение этого занятия приведу один простой практический пример с использованием дат и их сравнений:

from datetime import datetime
 
expiration_date = datetime(2025, 8, 15)
today = datetime.now()
 
if expiration_date > today:
    remaining_time = expiration_date - today
    print(f"Продукт годен. Осталось {remaining_time.days} дней.")
else:
    print("Срок годности истек!")

Здесь проверяется срок годности некоторого продукта с помощью операции сравнения дат. Если продукт еще годен, то вычисляется число оставшихся дней. Иначе, выводится сообщение "Срок годности истек!".

Курс по стандартной библиотеке: https://stepik.org/a/259466?utm_source=proproprogs

Видео по теме