Создание диапазона дат в Python - PullRequest
269 голосов
/ 14 июня 2009

Я хочу создать список дат, начиная с сегодняшнего дня и заканчивая произвольным числом дней, скажем, в моем примере 100 дней. Есть ли лучший способ сделать это, чем это?

import datetime

a = datetime.datetime.today()
numdays = 100
dateList = []
for x in range (0, numdays):
    dateList.append(a - datetime.timedelta(days = x))
print dateList

Ответы [ 18 ]

378 голосов
/ 14 июня 2009

немного лучше ...

base = datetime.datetime.today()
date_list = [base - datetime.timedelta(days=x) for x in range(0, numdays)]
188 голосов
/ 21 апреля 2014

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

Например pd.date_range():

import pandas as pd
datelist = pd.date_range(pd.datetime.today(), periods=100).tolist()

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

См. http://pandas.pydata.org/pandas-docs/stable/timeseries.html#generating-ranges-of-timestamps

Кроме того, он полностью поддерживает часовые пояса pytz и может плавно охватывать смену летнего и весеннего времени.

РЕДАКТИРОВАТЬ ОП:

Если вам нужны фактические даты Python, в отличие от отметок времени Pandas:

pd.date_range(end = pd.datetime.today(), periods = 100).to_pydatetime().tolist()

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

pd.date_range(pd.datetime.today(), periods=100).to_pydatetime().tolist()
52 голосов
/ 08 июля 2014

Получение диапазона дат между указанной датой начала и окончания (оптимизировано для сложности времени и пространства):

import datetime

start = datetime.datetime.strptime("21-06-2014", "%d-%m-%Y")
end = datetime.datetime.strptime("07-07-2014", "%d-%m-%Y")
date_generated = [start + datetime.timedelta(days=x) for x in range(0, (end-start).days)]

for date in date_generated:
    print date.strftime("%d-%m-%Y")
40 голосов
/ 14 июня 2009

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

import datetime

def date_generator():
  from_date = datetime.datetime.today()
  while True:
    yield from_date
    from_date = from_date - datetime.timedelta(days=1)

Этот генератор возвращает даты, начиная с сегодняшнего дня и возвращаясь назад один день за раз. Вот как взять первые 3 свидания:

>>> import itertools
>>> dates = itertools.islice(date_generator(), 3)
>>> list(dates)
[datetime.datetime(2009, 6, 14, 19, 12, 21, 703890), datetime.datetime(2009, 6, 13, 19, 12, 21, 703890), datetime.datetime(2009, 6, 12, 19, 12, 21, 703890)]

Преимущество этого подхода перед циклическим или списочным пониманием состоит в том, что вы можете возвращаться столько раз, сколько захотите.

Редактировать

Более компактная версия с использованием выражения генератора вместо функции:

date_generator = (datetime.datetime.today() - datetime.timedelta(days=i) for i in itertools.count())

Использование:

>>> dates = itertools.islice(date_generator, 3)
>>> list(dates)
[datetime.datetime(2009, 6, 15, 1, 32, 37, 286765), datetime.datetime(2009, 6, 14, 1, 32, 37, 286836), datetime.datetime(2009, 6, 13, 1, 32, 37, 286859)]
31 голосов
/ 16 сентября 2015

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

def date_range(start_date, end_date):
    for ordinal in range(start_date.toordinal(), end_date.toordinal()):
        yield datetime.date.fromordinal(ordinal)

Или, как предлагается в комментариях, вы можете создать такой список:

date_range = [
    datetime.date.fromordinal(ordinal) 
    for ordinal in range(
        start_date.toordinal(),
        end_date.toordinal(),
    )
]
28 голосов
/ 04 июля 2012

да, заново изобретать колесо .... просто поищите по форуму, и вы получите что-то вроде этого:

from dateutil import rrule
from datetime import datetime

list(rrule.rrule(rrule.DAILY,count=100,dtstart=datetime.now()))
15 голосов
/ 15 апреля 2016

Из заголовка этого вопроса я ожидал найти что-то вроде range(), что позволило бы мне указать две даты и создать список со всеми датами между ними. Таким образом, вам не нужно рассчитывать количество дней между этими двумя датами, если вы не знаете это заранее.

Так что с риском быть немного не по теме, эта однострочная работа делает:

import datetime
start_date = datetime.date(2011, 01, 01)
end_date   = datetime.date(2014, 01, 01)

dates_2011_2013 = [ start_date + datetime.timedelta(n) for n in range(int ((end_date - start_date).days))]

Все кредиты на этот ответ !

8 голосов
/ 15 сентября 2017

Вот немного другой ответ, основанный на ответе С. Лотта, который дает список дат между двумя датами start и end. В приведенном ниже примере с начала 2017 года по сегодняшний день.

start = datetime.datetime(2017,1,1)
end = datetime.datetime.today()
daterange = [start + datetime.timedelta(days=x) for x in range(0, (end-start).days)]
7 голосов
/ 18 мая 2011

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

from __builtin__ import range as _range
from datetime import datetime, timedelta

def range(*args):
    if len(args) != 3:
        return _range(*args)
    start, stop, step = args
    if start < stop:
        cmp = lambda a, b: a < b
        inc = lambda a: a + step
    else:
        cmp = lambda a, b: a > b
        inc = lambda a: a - step
    output = [start]
    while cmp(start, stop):
        start = inc(start)
        output.append(start)

    return output

print range(datetime(2011, 5, 1), datetime(2011, 10, 1), timedelta(days=30))
5 голосов
/ 24 апреля 2018

Если есть две даты и вам нужен диапазон, попробуйте

from dateutil import rrule, parser
date1 = '1995-01-01'
date2 = '1995-02-28'
datesx = list(rrule.rrule(rrule.DAILY, dtstart=parser.parse(date1), until=parser.parse(date2)))
...