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

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

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

Сравнение и сортировка дат

Даты сравниваются как числа — и потому сортируются, выбираются min и max и становятся ключами словаря. Разбираем операторы и честную сортировку без строковых сюрпризов.

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

В уроке 1 мы поймали строки на лжи: '9.10.2026' > '10.10.2026' вернуло True, потому что строки сравниваются посимвольно. Для дат это была бы катастрофа: сентябрь оказался бы «позже» октября. Объекты date и datetime сравниваются честно — операторами, как числа. Именно поэтому даты можно сортировать, выбирать из них минимум и максимум и строить на них проверки «просрочено или нет».

Операторы сравнения

Все шесть операторов работают: <, >, <=, >=, ==, !=. Сравнивать можно только объекты одного класса: date с date, datetime с datetime. Равенство тоже по значению — два разных объекта с одинаковыми полями равны.

дедлайн и отправка
from datetime import date

deadline = date(2026, 11, 1)
sent = date(2026, 10, 21)

print(deadline < sent)
print(sent == date(2026, 10, 21))
print(sent <= deadline)
Вывод
False
True
True

Сравнение идёт по полям: сначала годы, потом месяцы, потом дни — ровно как сравнивают числа, по разрядам. Поэтому даты разных лет и месяцев сравниваются за один оператор без ручных проверок. Один нюанс: спутать классы нельзя — datetime < date упадёт с TypeError: сравнение момента и даты не поддерживается, потому что это разные классы. Лечится приведением к общему классу: метод .date() из урока 2 срезает время, и сравнение проходит.

min, max и sorted

самая ранняя, самая поздняя, по порядку
from datetime import date

dates = [
    date(2026, 11, 1),
    date(2026, 10, 21),
    date(2026, 12, 5),
]

print(min(dates))
print(max(dates))
print(sorted(dates))
Вывод
2026-10-21
2026-12-05
[datetime.date(2026, 10, 21), datetime.date(2026, 11, 1), datetime.date(2026, 12, 5)]

min и max возвращают самую раннюю и самую позднюю дату, sorted — новый список по возрастанию (параметр reverse=True перевернёт). В печать списка заглянул repr: datetime.date(...) — то самое отладочное лицо даты из первого урока. Сортировка ничего не стоит программисту: не нужно писать функцию сравнения или разбирать строки — объекты уже сравнимы. Со строками дат такой номер не прошёл бы: список из «9.10.2026» и «10.10.2026» отсортировался бы по алфавиту, и октябрь встал бы раньше сентября.

Даты как ключи словаря

расписание по дням
from datetime import date

events = {
    date(2026, 10, 21): 'деплой',
    date(2026, 11, 1): 'релиз',
    date(2026, 10, 30): 'аудит',
}

print(events[date(2026, 10, 30)])

for day in sorted(events):
    print(day, events[day])
Вывод
аудит
2026-10-21 деплой
2026-10-30 аудит
2026-11-01 релиз

Ключом словаря может быть только неизменяемый и хешируемый объект — дата подходит идеально: events[date(2026, 10, 30)] достаёт событие по дню без перебора. Печать ключей идёт ISO-строкой, и в таком словаре удобно хранить всё, что привязано к календарю: события, курсы валют, списки дел. Дальше по курсу: урок 10 — isoformat, строковый формат, который сортируется как дата; урок 16 — возраст и разница в днях, где сравнение и timedelta работают в паре.

Сортировка записей, у которых дата внутри

Наивный sorted на списке словарей не сработает: словари между собой не сравниваются, Python честно откажется. Но почти всегда сортировать нужно не даты, а записи, у которых дата лежит внутри — заказы, счета, тикеты. Решение — параметр key: функция, которая вызывается для каждого элемента, и по её результату идёт сортировка. Одна строка с lambda превращает список словарей в хронологический список.

sort_records.py — сортировка по ключу
from datetime import date

events = [
    {'name': 'релиз', 'day': date(2026, 11, 1)},
    {'name': 'деплой', 'day': date(2026, 10, 21)},
    {'name': 'аудит', 'day': date(2026, 10, 28)},
]

for event in sorted(events, key=lambda item: item['day']):
    print(event['day'], event['name'])
Вывод
2026-10-21 деплой
2026-10-28 аудит
2026-11-01 релиз

Здесь стоит остановиться и подумать, а не просто скопировать. Параметр key говорит: «сравнивай элементы по тому, что вернёт эта функция». Именно поэтому сортировка записей работает так же надёжно, как сортировка дат, — сравниваются всё те же объекты date, а не строки и не словари. Побочная выгода: ключ можно усложнить. Отсортировать по дате, а при совпадении — по имени, — это key=lambda item: (item['day'], item['name']), и никаких отдельных функций сравнения писать не нужно.

Ближайшая дата к заданной

Отдельная задача, которая на проектной работе возникает чаще, чем кажется: есть список дат и есть опорная дата, надо найти ближайшую к ней. В общем виде задача выглядит так: взять расстояние от каждой даты до цели и выбрать минимальное. Расстояние считается через разницу в днях, а искать минимум умеет min с тем же параметром key.

nearest.py — ближайшая дата
from datetime import date

target = date(2026, 10, 25)
days = [date(2026, 10, 21), date(2026, 11, 1), date(2026, 10, 28)]

nearest = min(days, key=lambda d: abs((d - target).days))
print(nearest)
print(abs((nearest - target).days))
Вывод
2026-10-28
3

Модуль abs здесь не лишний: без него min нашёл бы самую раннюю дату вместо ближайшей, потому что отрицательные расстояния меньше положительных. А вот max с тем же ключом дал бы самую далёкую — иногда это тоже нужно, но называть это «ближайшей» нельзя. Если в списке есть и прошлое, и будущее, а вам нужна ближайшая именно в будущем, условие меняют: берут только даты позже цели.

mixed.py — строки и даты вместе
from datetime import date

items = [date(2026, 10, 21), '2026-10-22']

try:
    print(sorted(items))
except TypeError:
    print('смешанные типы не сравниваются')
Вывод
смешанные типы не сравниваются

Равенство — это не идентичность

Сравнение дат стоит различать с проверкой идентичности. Два объекта date с одинаковыми полями равны, но это разные объекты в памяти. Оператор is для дат бесполезен и почти всегда даёт False: он спрашивает, не один ли это объект, а не про поля. В словаре это не мешает, потому что там ключи сравниваются по значению, — а вот код вида if event.date() is today будет вести себя непредсказуемо.

equality.py — == и is
from datetime import date

a = date(2026, 10, 21)
b = date(2026, 10, 21)

print(a == b)
print(a is b)
Вывод
True
False

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

Сравнение дат, когда типы разные: ловушка TypeError

Сравнивать даты в Python приятно, пока не сравниваются разные типы. date и datetime — близкие родственники: datetime действительно подкласс date, и на первый взгляд сравнение должно работать. Но Python всё равно отказывает, потому что сравнение момента с датой бессмысленно: у datetime есть часы, минуты и секунды, а у date нет, и «раньше» тут не определено. Проверка date < datetime падает с TypeError — и, что важно для отладки, текст этой ошибки в Python 3.12 и 3.13 разный: в 3.12 это «can't compare datetime.datetime to datetime.date», в 3.13 — «'<' not supported between instances of 'datetime.date' and 'datetime.datetime'». Один и тот же код, одна и та же ошибка, два разных текста.

Из этого следует практическое правило: приводите обе стороны к одному типу до сравнения, а не ловите TypeError. Если работаете с датами из JSON или из базы — приведите их к date на границе входа, и дальше сравнивайте уже однородные значения. Намеренно ловить исключение здесь — плохая идея: сообщение об ошибке зависит от версии Python, и код, который на неё завязан, сломается при обновлении.

mixed_types.py — приводим к одному типу заранее
from datetime import date, datetime

day = date(2026, 10, 21)
moment = datetime(2026, 10, 21, 14, 30)

print(day < moment.date())
print(day == moment.date())
Вывод
False
True

И не забывайте про порядок: в Python даты сравниваются по календарю, то есть 2026-10-30 позже 2026-09-01. Для строк то же самое работает только при одинаковом формате во всех данных — и то, пока это ISO, где порядок цифр совпадает с хронологическим. Про то, почему такие строки удобно сортировать без разбора, — в уроке 10.

Что выведет код?

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

from datetime import date

dates = [
    date(2026, 11, 1),
    date(2026, 10, 21),
    date(2026, 12, 5),
]

print(min(dates), max(dates))
from datetime import date

dates = [date(2026, 12, 5), date(2026, 10, 21)]
print(sorted(dates))
from datetime import date

events = {
    date(2026, 11, 1): 'релиз',
    date(2026, 10, 21): 'деплой',
}

print(events[max(events)])
from datetime import date

events = [
    {'name': 'релиз', 'day': date(2026, 11, 1)},
    {'name': 'деплой', 'day': date(2026, 10, 21)},
]

for event in sorted(events, key=lambda item: item['day']):
    print(event['name'], event['day'])
Проверь себя
0 / 9

1. Что вернёт date(2026, 10, 21) < date(2026, 11, 1)?

2. Как сравниваются даты по полям?

3. Что произойдёт при сравнении datetime с date?

4. Что вернёт sorted(dates) для списка дат?

5. Почему даты можно использовать как ключи словаря?

6. Почему список строк '9.10.2026' и '10.10.2026' сортируется неверно?

7. Как отсортировать список словарей по дате, лежащей внутри записи?

8. Что вернёт print(a == b) и print(a is b) для двух date(2026, 10, 21)?

9. Как найти дату, ближайшую к заданной, среди списка?

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

Дан список дат — 14 ноября, 21 октября, 5 декабря и 1 сентября 2026 года — все вперемешку. Выведи самую раннюю, самую позднюю и весь список по возрастанию.

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

Как сравнить две даты в Python?

Обычными операторами: date(2026, 10, 21) < date(2026, 11, 1) вернёт True. Сравнение идёт по значению — годы, затем месяцы, затем дни. Единственное правило: классы должны совпадать, datetime с date напрямую не сравнивается.

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

Как отсортировать список дат?

Функцией sorted: sorted(dates) вернёт новый список по возрастанию, параметр reverse=True — по убыванию. Отдельная функция сравнения не нужна: объекты date и datetime уже сравнимы. Именно поэтому даты стоит держать как объекты, а не как строки.

Можно ли использовать дату как ключ словаря?

Да: date и datetime неизменяемы и хешируемы, поэтому словарь вида {date(2026, 10, 21): 'деплой'} работает — значение достаётся по дате без перебора. Обход в хронологическом порядке даёт for day in sorted(events).

Как найти ближайшую дату из списка?

min(dates) — самая ранняя, max(dates) — самая поздняя. Для «ближайшей к сегодня» сравнивают разницы через timedelta или берут минимум по ключу min(dates, key=...), но базовые min и max уже закрывают поиск крайних дат.

Урок 6: timedelta

Как отсортировать список заказов по дате, если дата лежит внутри записи?

Через параметр key: sorted(orders, key=lambda item: item['date']). Функция вызывается для каждой записи, и сортировка идёт по её результату — то есть по объекту date, а не по строке и не по самому словарю.

Как найти ближайшую к сегодняшнему дню дату из списка?

min(days, key=lambda d: abs((d - target).days)) — считаем расстояние в днях и берём минимум. Функция abs обязательна: без неё отрицательные расстояния до прошлых дат всегда «меньше», и min вернёт самую раннюю дату вместо ближайшей.

Урок 6: timedelta

Можно ли сравнить date с datetime, если дата и момент описывают один день?

Нет, получится TypeError: '<' not supported between instances of 'datetime.date' and 'datetime.datetime'. Приводите к общему классу: moment.date() даёт date, и тогда сравнение проходит. Ошибка здесь полезна — она всплывает сразу, а не превращается в неверный результат.

Урок 2: date, time и datetime

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

«Сравнение идёт по полям: сначала годы, потом месяцы, потом дни — ровно как сравнивают числа, по разрядам.»

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

TelegramVK

Что дальше

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

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

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