Python: get all months in range?

use datetime and timedelta standard Python's modules - without installing any new libraries

from datetime import datetime, timedelta

now = datetime(datetime.now().year, datetime.now().month, 1)
ctr = datetime(2010, 8, 1)
list = [ctr.strftime('%Y-%m-%d')]

while ctr <= now:
    ctr += timedelta(days=32)
    list.append( datetime(ctr.year, ctr.month, 1).strftime('%Y-%m-%d') )

I'm adding 32 days to enter new month every time (longest months has 31 days)


dateutil.relativedelta is handy here.

I've left the formatting out as an exercise.

from dateutil.relativedelta import relativedelta
import datetime

result = []

today = datetime.date.today()
current = datetime.date(2010, 8, 1)    

while current <= today:
    result.append(current)
    current += relativedelta(months=1)

I had a look at the dateutil documentation. Turns out it provides an even more convenient way than using dateutil.relativedelta: recurrence rules (examples)

For the task at hand, it's as easy as

from dateutil.rrule import *
from datetime import date

months = map(
    date.isoformat,
    rrule(MONTHLY, dtstart=date(2010, 8, 1), until=date.today())
)

The fine print

Note that we're cheating a little bit, here. The elements dateutil.rrule.rrule produces are of type datetime.datetime, even if we pass dtstart and until of type datetime.date, as we do above. I let map feed them to date's isoformat function, which just turns out to convert them to strings as if it were just dates without any time-of-day information.

Therefore, the seemingly equivalent list comprehension

[day.isoformat()
    for day in rrule(MONTHLY, dtstart=date(2010, 8, 1), until=date.today())]

would return a list like

['2010-08-01T00:00:00',
 '2010-09-01T00:00:00',
 '2010-10-01T00:00:00',
 '2010-11-01T00:00:00',
 ⋮
 '2015-12-01T00:00:00',
 '2016-01-01T00:00:00',
 '2016-02-01T00:00:00']

Thus, if we want to use a list comprehension instead of map, we have to do something like

[dt.date().isoformat()
    for dt in rrule(MONTHLY, dtstart=date(2010, 8, 1), until=date.today())]