tags:

views:

6343

answers:

4

Is there a way using Python's standard library to easily determine (i.e. one function call) the last day of a given month?

If the standard library doesn't support that, does the dateutil package support this?

+11  A: 

EDIT: See @Blair Conrad's answer for a cleaner solution


>>> import datetime
>>> datetime.date (2000, 2, 1) - datetime.timedelta (days = 1)
datetime.date(2000, 1, 31)
>>>
John Millikin
+4  A: 

EDIT: see my other answer. It has a better implementation than this one, which I leave here just in case someone's interested in seeing how one might "roll your own" calculator.

@John Millikin gives a good answer, with the added complication of calculating the first day of the next month.

The following isn't particularly elegant, but to figure out the last day of the month that any given date lives in, you could try:

def last_day_of_month(date):
    if date.month == 12:
        return date.replace(day=31)
    return date.replace(month=date.month+1, day=1) - datetime.timedelta(days=1)

>>> last_day_of_month(datetime.date(2002, 1, 17))
datetime.date(2002, 1, 31)
>>> last_day_of_month(datetime.date(2002, 12, 9))
datetime.date(2002, 12, 31)
>>> last_day_of_month(datetime.date(2008, 2, 14))
datetime.date(2008, 2, 29)
Blair Conrad
+42  A: 

I didn't notice this earlier when I was looking at the documentation for the calendar module, but a method called monthrange provides this information:

monthrange(year, month)
    Returns weekday of first day of the month and number of days in month, for the specified year and month.

>>> import calendar
>>> calendar.monthrange(2002,1)
(1, 31)
>>> calendar.monthrange(2008,2)
(4, 29)
>>> calendar.monthrange(2100,2)
(0, 28)

so:

calendar.monthrange(year, month)[1]

seems like the simplest way to go.

My previous answer still works, but is clearly suboptimal.

Blair Conrad
A: 

Another solution would be to do something like this:

from datetime import datetime

def last_day_of_month(year, month):
        """ Work out the last day of the month """
        last_days = [31, 30, 29, 28, 27]
        for i in last_days:
                try:
                        end = datetime(year, month, i)
                except ValueError:
                        continue
                else:
                        return end.date()
        return None

And use the function like this:

>>> 
>>> last_day_of_month(2008, 2)
datetime.date(2008, 2, 29)
>>> last_day_of_month(2009, 2)
datetime.date(2009, 2, 28)
>>> last_day_of_month(2008, 11)
datetime.date(2008, 11, 30)
>>> last_day_of_month(2008, 12)
datetime.date(2008, 12, 31)