# datetime – Creating a range of dates in Python

## The Question :

421 people think this question is useful

I want to create a list of dates, starting with today, and going back an arbitrary number of days, say, in my example 100 days. Is there a better way to do it than this?

import datetime

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



519 people think this answer is useful

Marginally better…

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



296 people think this answer is useful

Pandas is great for time series in general, and has direct support for date ranges.

For example pd.date_range():

import pandas as pd
from datetime import datetime

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



It also has lots of options to make life easier. For example if you only wanted weekdays, you would just swap in bdate_range.

In addition it fully supports pytz timezones and can smoothly span spring/autumn DST shifts.

EDIT by OP:

If you need actual python datetimes, as opposed to Pandas timestamps:

import pandas as pd
from datetime import datetime

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

#OR

pd.date_range(start="2018-09-09",end="2020-02-02")



This uses the “end” parameter to match the original question, but if you want descending dates:

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



94 people think this answer is useful

Get range of dates between specified start and end date (Optimized for time & space complexity):

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



45 people think this answer is useful

You can write a generator function that returns date objects starting from today:

import datetime

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



This generator returns dates starting from today and going backwards one day at a time. Here is how to take the first 3 dates:

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



The advantage of this approach over a loop or list comprehension is that you can go back as many times as you want.

Edit

A more compact version using a generator expression instead of a function:

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



Usage:

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



35 people think this answer is useful

yeah, reinvent the wheel…. just search the forum and you’ll get something like this:

from dateutil import rrule
from datetime import datetime

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



34 people think this answer is useful

You can also use the day ordinal to make it simpler:

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



Or as suggested in the comments you can create a list like this:

date_range = [
datetime.date.fromordinal(ordinal)
for ordinal in range(
start_date.toordinal(),
end_date.toordinal(),
)
]



18 people think this answer is useful

From the title of this question I was expecting to find something like range(), that would let me specify two dates and create a list with all the dates in between. That way one does not need to calculate the number of days between those two dates, if one does not know it beforehand.

So with the risk of being slightly off-topic, this one-liner does the job:

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



13 people think this answer is useful

Here’s a slightly different answer building off of S.Lott’s answer that gives a list of dates between two dates start and end. In the example below, from the start of 2017 to today.

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 people think this answer is useful

If there are two dates and you need the range try

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



7 people think this answer is useful

A bit of a late answer I know, but I just had the same problem and decided that Python’s internal range function was a bit lacking in this respect so I’ve overridden it in a util module of mine.

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



7 people think this answer is useful

Based on answers I wrote for myself this:

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



Output:

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



The difference is that I get the ‘date‘ object, not the ‘datetime.datetime‘ one.

5 people think this answer is useful

Here is gist I created, from my own code, this might help. (I know the question is too old, but others can use it)

https://gist.github.com/2287345

(same thing below)

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



4 people think this answer is useful

Here’s a one liner for bash scripts to get a list of weekdays, this is python 3. Easily modified for whatever, the int at the end is the number of days in the past you want.

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



Here is a variant to provide a start (or rather, end) date

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



Here is a variant for arbitrary start and end dates. not that this isn’t terribly efficient, but is good for putting in a for loop in a 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



3 people think this answer is useful

Matplotlib related

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)



3 people think this answer is useful

I know this has been answered, but I’ll put down my answer for historical purposes, and since I think it is straight forward.

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



Sure it won’t win anything like code-golf, but I think it is elegant.

2 people think this answer is useful

Another example that counts forwards or backwards, starting from Sandeep’s answer.

from datetime import date, datetime, timedelta
from typing import Sequence
def range_of_dates(start_of_range: date, end_of_range: date) -> Sequence[date]:

if start_of_range <= end_of_range:
return [
start_of_range + timedelta(days=x)
for x in range(0, (end_of_range - start_of_range).days + 1)
]
return [
start_of_range - timedelta(days=x)
for x in range(0, (start_of_range - end_of_range).days + 1)
]

start_of_range = datetime.today().date()
end_of_range = start_of_range + timedelta(days=3)
date_range = range_of_dates(start_of_range, end_of_range)
print(date_range)



gives

[datetime.date(2019, 12, 20), datetime.date(2019, 12, 21), datetime.date(2019, 12, 22), datetime.date(2019, 12, 23)]



and

start_of_range = datetime.today().date()
end_of_range = start_of_range - timedelta(days=3)
date_range = range_of_dates(start_of_range, end_of_range)
print(date_range)



gives

[datetime.date(2019, 12, 20), datetime.date(2019, 12, 19), datetime.date(2019, 12, 18), datetime.date(2019, 12, 17)]



Note that the start date is included in the return, so if you want four total dates, use timedelta(days=3)

1 people think this answer is useful
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



1 people think this answer is useful

A monthly date range generator with datetime and dateutil. Simple and easy to understand:

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)



0 people think this answer is useful
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()



0 people think this answer is useful

From above answers i created this example for date generator

import datetime
date = datetime.datetime.now()
time = date.time()
def date_generator(date, delta):
counter =0
date = date - datetime.timedelta(days=delta)
while counter <= delta:
yield date
date = date + datetime.timedelta(days=1)
counter +=1

for date in date_generator(date, 30):
if date.date() != datetime.datetime.now().date():
start_date = datetime.datetime.combine(date, datetime.time())
end_date = datetime.datetime.combine(date, datetime.time.max)
else:
start_date = datetime.datetime.combine(date, datetime.time())
end_date = datetime.datetime.combine(date, time)
print('start_date---->',start_date,'end_date---->',end_date)



0 people think this answer is useful

I thought I’d throw in my two cents with a simple (and not complete) implementation of a date range:

from datetime import date, timedelta, datetime

class DateRange:
def __init__(self, start, end, step=timedelta(1)):
self.start = start
self.end = end
self.step = step

def __iter__(self):
start = self.start
step = self.step
end = self.end

n = int((end - start) / step)
d = start

for _ in range(n):
yield d
d += step

def __contains__(self, value):
return (
(self.start <= value < self.end) and
((value - self.start) % self.step == timedelta(0))
)