Creating a range of dates in Python

Viewed 752210

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
23 Answers

Marginally better...

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

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

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

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

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.

A generic method that allows to create date ranges on parameterised window size(day, minute, hour, seconds):

from datetime import datetime, timedelta

def create_date_ranges(start, end, **interval):
    start_ = start
    while start_ < end:
        end_ = start_ + timedelta(**interval)
        yield (start_, min(end_, end))
        start_ = end_

Tests:

def main():
    tests = [
        ('2021-11-15:00:00:00', '2021-11-17:13:00:00', {'days': 1}),
        ('2021-11-15:00:00:00', '2021-11-16:13:00:00', {'hours': 12}),
        ('2021-11-15:00:00:00', '2021-11-15:01:45:00', {'minutes': 30}),
        ('2021-11-15:00:00:00', '2021-11-15:00:01:12', {'seconds': 30})
    ]
    for t in tests:
        print("\nInterval: %s, range(%s to %s)" % (t[2], t[0], t[1]))
        start = datetime.strptime(t[0], '%Y-%m-%d:%H:%M:%S')
        end =  datetime.strptime(t[1], '%Y-%m-%d:%H:%M:%S')
        ranges = list(create_date_ranges(start, end, **t[2]))        
        x = list(map(
            lambda x: (x[0].strftime('%Y-%m-%d:%H:%M:%S'), x[1].strftime('%Y-%m-%d:%H:%M:%S')),
            ranges
        ))
        print(x)
main()

Test output:

Interval: {'days': 1}, range(2021-11-15:00:00:00 to 2021-11-17:13:00:00)
[('2021-11-15:00:00:00', '2021-11-16:00:00:00'), ('2021-11-16:00:00:00', '2021-11-17:00:00:00'), ('2021-11-17:00:00:00', '2021-11-17:13:00:00')]

Interval: {'hours': 12}, range(2021-11-15:00:00:00 to 2021-11-16:13:00:00)
[('2021-11-15:00:00:00', '2021-11-15:12:00:00'), ('2021-11-15:12:00:00', '2021-11-16:00:00:00'), ('2021-11-16:00:00:00', '2021-11-16:12:00:00'), ('2021-11-16:12:00:00', '2021-11-16:13:00:00')]

Interval: {'minutes': 30}, range(2021-11-15:00:00:00 to 2021-11-15:01:45:00)
[('2021-11-15:00:00:00', '2021-11-15:00:30:00'), ('2021-11-15:00:30:00', '2021-11-15:01:00:00'), ('2021-11-15:01:00:00', '2021-11-15:01:30:00'), ('2021-11-15:01:30:00', '2021-11-15:01:45:00')]

Interval: {'seconds': 30}, range(2021-11-15:00:00:00 to 2021-11-15:00:01:12)
[('2021-11-15:00:00:00', '2021-11-15:00:00:30'), ('2021-11-15:00:00:30', '2021-11-15:00:01:00'), ('2021-11-15:00:01:00', '2021-11-15:00:01:12')]

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)

from datetime import datetime , timedelta, timezone


start_date = '2022_01_25'
end_date = '2022_01_30'

start = datetime.strptime(start_date, "%Y_%m_%d")
print(type(start))
end =  datetime.strptime(end_date, "%Y_%m_%d")
##pDate = str(pDate).replace('-', '_')
number_of_days = (end - start).days

print("number_of_days: ", number_of_days)

##
date_list = []
for day in range(number_of_days):
    a_date = (start + timedelta(days = day)).astimezone(timezone.utc)
    a_date = a_date.strftime('%Y-%m-%d')
    date_list.append(a_date)

print(date_list)

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)

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)

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