Get tuple of the first and last days of the last N months I am trying to get a tuple of date (or datetime) objects over the last N months.

My thought was to use the dateutil package with something like this:

def last_n_months(n=12, ending=None):
    """Return a list of tuples of the first/last day of the month
    for the last N months    
    """
    from datetime import date
    from dateutil.rrule import rrule, MONTHLY
    from dateutil.relativedelta import relativedelta

    if not ending:
        ending = date.today()

    # set the ending date to the last day of the month
    ending = ending + relativedelta(months=+1, days=-ending.day)

    # starting is the first day of the month N months ago
    starting = ending - relativedelta(months=n, day=1)

    months = list(rrule(MONTHLY, bymonthday=(1, -1), dtstart=starting,
                        until=ending))

    # we return pairs of dates like this: (1st day of month, last day of month)
    months = zip(months[::2], months[1::2])

    return months


Example usage:

    &gt;&gt;&gt; from datetime import date, timedelta

    # get last two months as a degenerate example
    &gt;&gt;&gt; l2n = last_n_months(2, ending=date(2012, 01, 01))
    &gt;&gt;&gt; map(lambda x: [x[0].year, x[0].month, x[0].day], l2n)
    [[2011, 11, 1], [2011, 12, 1], [2012, 1, 1]]
    &gt;&gt;&gt; map(lambda x: [x[1].year, x[1].month, x[1].day], l2n)
    [[2011, 11, 30], [2011, 12, 31], [2012, 1, 31]]

    &gt;&gt;&gt; l24n = last_n_months(24, ending=date(2012,03,16))
    &gt;&gt;&gt; len(l24n) # inclusive of current month
    25

    # every tuple starts with the first day of the month
    &gt;&gt;&gt; all(x[0].day == 1 for x in l24n)
    True

    # every tuple ends with the last day of the month
    &gt;&gt;&gt; all((x[1] +timedelta(days=1)).month != x[1].month for x in l24n)
    True

    # every tuple is the same month
    &gt;&gt;&gt; all(x[0].month == x[1].month for x in l24n)
    True


I am posting it here to see if anyone has a better solution than this (and perhaps see if this yields some off-by-one sort of error that I haven't thought of).

Is there a simpler or faster solution than this?
def last_n_months(n=12, ending=None):
    """Return a list of tuples of the first/last day of the month
    for the last N months    
    """
    from datetime import date
    from dateutil.rrule import rrule, MONTHLY
    from dateutil.relativedelta import relativedelta


It is better to import outside of the function. Typically imports go at the top of the file.

    if not ending:


You should check for none like: if ending is not None: just to be explicit about what you are checking for.

        ending = date.today()

    # set the ending date to the last day of the month
    ending = ending + relativedelta(months=+1, days=-ending.day)


Modifying ending rubs me the wrong way. 

    # starting is the first day of the month N months ago
    starting = ending - relativedelta(months=n, day=1)

    months = list(rrule(MONTHLY, bymonthday=(1, -1), dtstart=starting,
                        until=ending))

    # we return pairs of dates like this: (1st day of month, last day of month)
    months = zip(months[::2], months[1::2])

    return months


You can combine these two lines