Вопрос-Ответ

Iterating through a range of dates in Python

Перебор диапазона дат в Python

У меня есть следующий код для этого, но как я могу сделать это лучше? Прямо сейчас я думаю, что это лучше, чем вложенные циклы, но это начинает становиться однострочным для Perl, когда у вас есть генератор в понимании списка.

day_count = (end_date - start_date).days + 1
for single_date in [d for d in (start_date + timedelta(n) for n in range(day_count)) if d <= end_date]:
print strftime("%Y-%m-%d", single_date.timetuple())

Примечания


  • На самом деле я не использую это для печати. Это просто для демонстрации.

  • Переменные start_date и end_date являются datetime.date объектами, потому что мне не нужны временные метки. (Они будут использоваться для создания отчета).

Пример вывода

Для получения даты начала 2009-05-30 и даты окончания 2009-06-09:

2009-05-30
2009-05-31
2009-06-01
2009-06-02
2009-06-03
2009-06-04
2009-06-05
2009-06-06
2009-06-07
2009-06-08
2009-06-09
Переведено автоматически
Ответ 1

Почему существуют две вложенные итерации? Для меня это создает один и тот же список данных только с одной итерацией:

for single_date in (start_date + timedelta(n) for n in range(day_count)):
print ...

Список не сохраняется, повторяется только один генератор. Также "if" в генераторе кажется ненужным.

В конце концов, для линейной последовательности должен требоваться только один итератор, а не два.

Обновление после обсуждения с Джоном Мачином:

Возможно, самым элегантным решением является использование функции генератора для полного скрытия / абстрагирования итерации по диапазону дат:

from datetime import date, timedelta

def daterange(start_date, end_date):
for n in range(int((end_date - start_date).days)):
yield start_date + timedelta(n)

start_date = date(2013, 1, 1)
end_date = date(2015, 6, 2)
for single_date in daterange(start_date, end_date):
print(single_date.strftime("%Y-%m-%d"))

ПРИМЕЧАНИЕ: Для согласованности со встроенной range() функцией эта итерация останавливается перед достижением end_date. Итак, для инклюзивной итерации используйте следующий день, как вы бы сделали с range().

Ответ 2

Это могло бы быть более понятным:

from datetime import date, timedelta

start_date = date(2019, 1, 1)
end_date = date(2020, 1, 1)
delta = timedelta(days=1)
while start_date <= end_date:
print(start_date.strftime("%Y-%m-%d"))
start_date += delta
Ответ 3

Используйте dateutil библиотеку:

from datetime import date
from dateutil.rrule import rrule, DAILY

a = date(2009, 5, 30)
b = date(2009, 6, 9)

for dt in rrule(DAILY, dtstart=a, until=b):
print dt.strftime("%Y-%m-%d")

Эта библиотека Python обладает множеством более продвинутых функций, некоторые из которых очень полезны, например, relative deltas- и реализована в виде отдельного файла (модуля), который легко включается в проект.

Ответ 4

Pandas отлично подходит для временных рядов в целом и имеет прямую поддержку диапазонов дат.

import pandas as pd
daterange = pd.date_range(start_date, end_date)

Затем вы можете выполнить цикл по диапазону дат, чтобы напечатать дату:

for single_date in daterange:
print (single_date.strftime("%Y-%m-%d"))

В нем также есть множество опций, упрощающих жизнь. Например, если вам нужны только дни недели, вы бы просто поменяли местами bdate_range . Смотрите http://pandas.pydata.org/pandas-docs/stable/timeseries.html#generating-ranges-of-timestamps

Мощь Pandas на самом деле заключается в ее фреймах данных, которые поддерживают векторизованные операции (очень похожие на numpy), что делает операции с большими объемами данных очень быстрыми и простыми.

РЕДАКТИРОВАТЬ: вы также можете полностью пропустить цикл for и просто распечатать его напрямую, что проще и эффективнее:

print(daterange)
python datetime