Создание диапазона дат в Python

Я хочу создать список дат, начиная с сегодняшнего дня, и вернуться к произвольному количеству дней, скажем, в моем примере 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

Ответ 1

Маргинально лучше...

base = datetime.datetime.today()
date_list = [base - datetime.timedelta(days=x) for x in range(numdays)]

Ответ 2

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

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

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

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

См. документацию по диапазону дат

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

ОБНОВЛЕНИЕ OP:

Если вам нужны реальные даты 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()

Ответ 3

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

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")

Ответ 4

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

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)]

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

Edit

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

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)]

Ответ 5

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

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(),
    )
]

Ответ 6

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

from dateutil import rrule
from datetime import datetime

list(rrule.rrule(rrule.DAILY,count=100,dtstart=datetime.now()))

Ответ 7

Из названия этого вопроса я ожидал найти что-то вроде 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

Здесь немного другое ответное построение ответа S.Lott, которое дает список дат между двумя датами 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)]

Ответ 9

Немного позднего ответа, который я знаю, но у меня была такая же проблема, и я решил, что функция внутреннего диапазона 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))

Ответ 10

Вот суть, которую я создал, из моего собственного кода, это может помочь. (Я знаю, что вопрос слишком стар, но другие могут его использовать)

https://gist.github.com/2287345

(то же самое ниже)

import datetime
from time import mktime

def convert_date_to_datetime(date_object):
    date_tuple = date_object.timetuple()
    date_timestamp = mktime(date_tuple)
    return datetime.datetime.fromtimestamp(date_timestamp)

def date_range(how_many=7):
    for x in range(0, how_many):
        some_date = datetime.datetime.today() - datetime.timedelta(days=x)
        some_datetime = convert_date_to_datetime(some_date.date())
        yield some_datetime

def pick_two_dates(how_many=7):
    a = b = convert_date_to_datetime(datetime.datetime.now().date())
    for each_date in date_range(how_many):
        b = a
        a = each_date
        if a == b:
            continue
        yield b, a

Ответ 11

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

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)))

Ответ 12

Здесь один liner для bash скриптов, чтобы получить список будних дней, это python 3. Легко измененный для любого, int в конце - это количество дней в прошлом, которое вы хотите.

python -c "import sys,datetime; print('\n'.join([(datetime.datetime.today() - datetime.timedelta(days=x)).strftime(\"%Y/%m/%d\") for x in range(0,int(sys.argv[1])) if (datetime.datetime.today() - datetime.timedelta(days=x)).isoweekday()<6]))" 10

Вот вариант, чтобы указать дату начала (или, вернее, конца)

python -c "import sys,datetime; print('\n'.join([(datetime.datetime.strptime(sys.argv[1],\"%Y/%m/%d\") - datetime.timedelta(days=x)).strftime(\"%Y/%m/%d \") for x in range(0,int(sys.argv[2])) if (datetime.datetime.today() - datetime.timedelta(days=x)).isoweekday()<6]))" 2015/12/30 10

Вот вариант для произвольной даты начала и окончания. не то, что это не очень эффективно, но хорошо для ввода цикла for в bash script:

python -c "import sys,datetime; print('\n'.join([(datetime.datetime.strptime(sys.argv[1],\"%Y/%m/%d\") + datetime.timedelta(days=x)).strftime(\"%Y/%m/%d\") for x in range(0,int((datetime.datetime.strptime(sys.argv[2], \"%Y/%m/%d\") - datetime.datetime.strptime(sys.argv[1], \"%Y/%m/%d\")).days)) if (datetime.datetime.strptime(sys.argv[1], \"%Y/%m/%d\") + datetime.timedelta(days=x)).isoweekday()<6]))" 2015/12/15 2015/12/30

Ответ 13

Соответствие Matplotlib

from matplotlib.dates import drange
import datetime

base = datetime.date.today()
end  = base + datetime.timedelta(days=100)
delta = datetime.timedelta(days=1)
l = drange(base, end, delta)

Ответ 14

Исходя из ответов, я написал для себя это:

import datetime;
print [(datetime.date.today() - datetime.timedelta(days=x)).strftime('%Y-%m-%d') for x in range(-5, 0)]

Выход:

['2017-12-11', '2017-12-10', '2017-12-09', '2017-12-08', '2017-12-07']

Разница в том, что я получаю объект date, а не datetime.datetime.

Ответ 15

Я знаю, что на это ответили, но я запишу свой ответ в исторических целях, и, поскольку я думаю, что это прямо вперед.

import numpy as np
import datetime as dt
listOfDates=[date for date in np.arange(firstDate,lastDate,dt.timedelta(days=x))]

Конечно, это не выиграет ничего, как Code-Golf, но я думаю, что это элегантно.

Ответ 16

from datetime import datetime, timedelta
from dateutil import parser
def getDateRange(begin, end):
    """  """
    beginDate = parser.parse(begin)
    endDate =  parser.parse(end)
    delta = endDate-beginDate
    numdays = delta.days + 1
    dayList = [datetime.strftime(beginDate + timedelta(days=x), '%Y%m%d') for x in range(0, numdays)]
    return dayList

Ответ 17

Ежемесячный генератор диапазонов дат с dateutil datetime и dateutil. Просто и легко понять:

import datetime as dt
from dateutil.relativedelta import relativedelta

def month_range(start_date, n_months):
        for m in range(n_months):
            yield start_date + relativedelta(months=+m)

Ответ 18

import datetime    
def date_generator():
    cur = base = datetime.date.today()
    end  = base + datetime.timedelta(days=100)
    delta = datetime.timedelta(days=1)
    while(end>base):
        base = base+delta
        print base

date_generator()