На этом шаге мы рассмотрим реализацию этой задачи.
У вас есть код, которому необходимо пройти в цикле по каждой дате текущего месяца, и вам нужен эффективный способ поиска диапазонов дат.
Прохождение в цикле по датам не требует предварительного создания списка всех дат. Вы можете просто вычислить стартовую и конечную даты в диапазоне, а затем использовать объекты datetime.timedelta, инкрементируя дату.
Вот функция, которая принимает любой объект datetime и возвращает кортеж, содержащий первую дату месяца и начальную дату следующего месяца:
>>> from datetime import datetime, date, timedelta >>> import calendar >>> def get_month_range(start_date=None): if start_date is None: start_date = date.today().replace(day=1) _, days_in_month = calendar.monthrange(start_date.year, start_date.month) end_date = start_date + timedelta(days=days_in_month) return (start_date, end_date) >>> a_day = timedelta(days=1) >>> first_day, last_day = get_month_range() >>> while first_day < last_day: print(first_day) first_day += a_day 2026-04-01 2026-04-02 2026-04-03 2026-04-04 2026-04-05 2026-04-06 2026-04-07 2026-04-08 2026-04-09 2026-04-10 2026-04-11 2026-04-12 2026-04-13 2026-04-14 2026-04-15 2026-04-16 2026-04-17 2026-04-18 2026-04-19 2026-04-20 2026-04-21 2026-04-22 2026-04-23 2026-04-24 2026-04-25 2026-04-26 2026-04-27 2026-04-28 2026-04-29 2026-04-30 >>>
Этот рецепт работает так: сначала вычисляется дата, соответствующая первому дню месяца. Быстрый способ сделать это - использовать метод replace() объектов date или datetime, чтобы присвоить атрибуту days значение 1. Приятно, что метод replace() создает объект того же типа, к которому он был применен. В данном случае, поскольку на входе у нас был экземпляр date, результат тоже является экземпляром date. Точно так же мы бы получили экземпляр datetime, если бы на входе у нас был экземпляр datetime.
Затем функция calendar.monthrange() используется для нахождения количества дней в рассматриваемом месяце. Модуль calendar весьма полезен для получения базовых данных о календарях. Функция monthrange() возвращает кортеж, который содержит день недели и количество дней в месяце.
Когда мы знаем количество дней в месяце, конечная дата вычисляется путем добавления соответствующего timedelta к стартовой дате. Тонкий, но важный аспект этого рецепта - конечная дата не включается в диапазон (на самом деле это первая дата следующего месяца). Это отражает присущее срезам и диапазонам Python поведение, которое также не подразумевает включение последнего элемента.
Чтобы пройти в цикле по диапазону дат, используются стандартные математические операции и операторы сравнения. Например, экземпляр timedelta может быть использован для инкрементирования даты. Оператор < используется для проверки того, не достигнута ли конечная дата.
В идеальном случае стоит создать функцию, которая будет работать как встроенная range(), но с датами. К счастью, есть чрезвычайно простой способ сделать это с помощью генератора:
>>> for d in date_range(datetime(2012, 9, 1), datetime(2012,10,1), timedelta(hours=6)): print(d) 2012-09-01 00:00:00 2012-09-01 06:00:00 2012-09-01 12:00:00 2012-09-01 18:00:00 2012-09-02 00:00:00 2012-09-02 06:00:00 2012-09-02 12:00:00 2012-09-02 18:00:00 2012-09-03 00:00:00 2012-09-03 06:00:00 2012-09-03 12:00:00 2012-09-03 18:00:00 2012-09-04 00:00:00 2012-09-04 06:00:00 2012-09-04 12:00:00 2012-09-04 18:00:00 2012-09-05 00:00:00 2012-09-05 06:00:00 2012-09-05 12:00:00 2012-09-05 18:00:00 2012-09-06 00:00:00 2012-09-06 06:00:00 2012-09-06 12:00:00 2012-09-06 18:00:00 2012-09-07 00:00:00 2012-09-07 06:00:00 2012-09-07 12:00:00 2012-09-07 18:00:00 2012-09-08 00:00:00 2012-09-08 06:00:00 2012-09-08 12:00:00 2012-09-08 18:00:00 2012-09-09 00:00:00 2012-09-09 06:00:00 2012-09-09 12:00:00 2012-09-09 18:00:00 2012-09-10 00:00:00 2012-09-10 06:00:00 2012-09-10 12:00:00 2012-09-10 18:00:00 2012-09-11 00:00:00 2012-09-11 06:00:00 2012-09-11 12:00:00 2012-09-11 18:00:00 2012-09-12 00:00:00 2012-09-12 06:00:00 2012-09-12 12:00:00 2012-09-12 18:00:00 2012-09-13 00:00:00 2012-09-13 06:00:00 2012-09-13 12:00:00 2012-09-13 18:00:00 2012-09-14 00:00:00 2012-09-14 06:00:00 2012-09-14 12:00:00 2012-09-14 18:00:00 2012-09-15 00:00:00 2012-09-15 06:00:00 2012-09-15 12:00:00 2012-09-15 18:00:00 2012-09-16 00:00:00 2012-09-16 06:00:00 2012-09-16 12:00:00 2012-09-16 18:00:00 2012-09-17 00:00:00 2012-09-17 06:00:00 2012-09-17 12:00:00 2012-09-17 18:00:00 2012-09-18 00:00:00 2012-09-18 06:00:00 2012-09-18 12:00:00 2012-09-18 18:00:00 2012-09-19 00:00:00 2012-09-19 06:00:00 2012-09-19 12:00:00 2012-09-19 18:00:00 2012-09-20 00:00:00 2012-09-20 06:00:00 2012-09-20 12:00:00 2012-09-20 18:00:00 2012-09-21 00:00:00 2012-09-21 06:00:00 2012-09-21 12:00:00 2012-09-21 18:00:00 2012-09-22 00:00:00 2012-09-22 06:00:00 2012-09-22 12:00:00 2012-09-22 18:00:00 2012-09-23 00:00:00 2012-09-23 06:00:00 2012-09-23 12:00:00 2012-09-23 18:00:00 2012-09-24 00:00:00 2012-09-24 06:00:00 2012-09-24 12:00:00 2012-09-24 18:00:00 2012-09-25 00:00:00 2012-09-25 06:00:00 2012-09-25 12:00:00 2012-09-25 18:00:00 2012-09-26 00:00:00 2012-09-26 06:00:00 2012-09-26 12:00:00 2012-09-26 18:00:00 2012-09-27 00:00:00 2012-09-27 06:00:00 2012-09-27 12:00:00 2012-09-27 18:00:00 2012-09-28 00:00:00 2012-09-28 06:00:00 2012-09-28 12:00:00 2012-09-28 18:00:00 2012-09-29 00:00:00 2012-09-29 06:00:00 2012-09-29 12:00:00 2012-09-29 18:00:00 2012-09-30 00:00:00 2012-09-30 06:00:00 2012-09-30 12:00:00 2012-09-30 18:00:00 >>>
Повторимся, самое большое преимущество такой реализации в том, что датами и временем можно манипулировать с помощью стандартных математических операторов и операторов сравнения.
На следующем шаге мы рассмотрим конвертирование строк в даты и время.