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?
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?
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.
Just to be clear, monthrange
supports leap years as well:
>>> from calendar import monthrange
>>> monthrange(2012, 2)
(2, 29)
My previous answer still works, but is clearly suboptimal.
If you don\'t want to import the calendar
module, a simple two-step function can also be:
import datetime
def last_day_of_month(any_day):
next_month = any_day.replace(day=28) + datetime.timedelta(days=4) # this will never fail
return next_month - datetime.timedelta(days=next_month.day)
Outputs:
>>> for month in range(1, 13):
... print last_day_of_month(datetime.date(2012, month, 1))
...
2012-01-31
2012-02-29
2012-03-31
2012-04-30
2012-05-31
2012-06-30
2012-07-31
2012-08-31
2012-09-30
2012-10-31
2012-11-30
2012-12-31
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)
>>>
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)
This is actually pretty easy with dateutil.relativedelta
(package python-datetutil for pip). day=31
will always always return the last day of the month.
Example:
from datetime import datetime
from dateutil.relativedelta import relativedelta
date_in_feb = datetime.datetime(2013, 2, 21)
print datetime.datetime(2013, 2, 21) + relativedelta(day=31) # End-of-month
>>> datetime.datetime(2013, 2, 28, 0, 0)
Using relativedelta
you would get last date of month like this:
from dateutil.relativedelta import relativedelta
last_date_of_month = datetime(mydate.year,mydate.month,1)+relativedelta(months=1,days=-1)
The idea is to get the fist day of month and use relativedelta
to go 1 month ahead and 1 day back so you would get the last day of the month you wanted.
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)
from datetime import timedelta
(any_day.replace(day=1) + timedelta(days=32)).replace(day=1) - timedelta(days=1)
>>> import datetime
>>> import calendar
>>> date = datetime.datetime.now()
>>> print date
2015-03-06 01:25:14.939574
>>> print date.replace(day = 1)
2015-03-01 01:25:14.939574
>>> print date.replace(day = calendar.monthrange(date.year, date.month)[1])
2015-03-31 01:25:14.939574
if you are willing to use an external library, check out http://crsmithdev.com/arrow/
U can then get the last day of the month with:
import arrow
arrow.utcnow().ceil(\'month\').date()
This returns a date object which you can then do your manipulation.
To get the last date of the month we do something like this:
from datetime import date, timedelta
import calendar
last_day = date.today().replace(day=calendar.monthrange(date.today().year, date.today().month)[1])
Now to explain what we are doing here we will break it into two parts:
first is getting the number of days of the current month for which we use monthrange which Blair Conrad has already mentioned his solution:
calendar.monthrange(date.today().year, date.today().month)[1]
second is getting the last date itself which we do with the help of replace e.g
>>> date.today()
datetime.date(2017, 1, 3)
>>> date.today().replace(day=31)
datetime.date(2017, 1, 31)
and when we combine them as mentioned on the top we get a dynamic solution.
import datetime
now = datetime.datetime.now()
start_month = datetime.datetime(now.year, now.month, 1)
date_on_next_month = start_month + datetime.timedelta(35)
start_next_month = datetime.datetime(date_on_next_month.year, date_on_next_month.month, 1)
last_day_month = start_next_month - datetime.timedelta(1)
For me it\'s the simplest way:
selected_date = date(some_year, some_month, some_day)
if selected_date.month == 12: # December
last_day_selected_month = date(selected_date.year, selected_date.month, 31)
else:
last_day_selected_month = date(selected_date.year, selected_date.month + 1, 1) - timedelta(days=1)
The easiest way (without having to import calendar), is to get the first day of the next month, and then subtract a day from it.
import datetime as dt
from dateutil.relativedelta import relativedelta
thisDate = dt.datetime(2017, 11, 17)
last_day_of_the_month = dt.datetime(thisDate.year, (thisDate + relativedelta(months=1)).month, 1) - dt.timedelta(days=1)
print last_day_of_the_month
Output:
datetime.datetime(2017, 11, 30, 0, 0)
PS: This code runs faster as compared to the import calendar
approach; see below:
import datetime as dt
import calendar
from dateutil.relativedelta import relativedelta
someDates = [dt.datetime.today() - dt.timedelta(days=x) for x in range(0, 10000)]
start1 = dt.datetime.now()
for thisDate in someDates:
lastDay = dt.datetime(thisDate.year, (thisDate + relativedelta(months=1)).month, 1) - dt.timedelta(days=1)
print (\'Time Spent= \', dt.datetime.now() - start1)
start2 = dt.datetime.now()
for thisDate in someDates:
lastDay = dt.datetime(thisDate.year,
thisDate.month,
calendar.monthrange(thisDate.year, thisDate.month)[1])
print (\'Time Spent= \', dt.datetime.now() - start2)
OUTPUT:
Time Spent= 0:00:00.097814
Time Spent= 0:00:00.109791
This code assumes that you want the date of the last day of the month (i.e., not just the DD part, but the entire YYYYMMDD date)
You can calculate the end date yourself. the simple logic is to subtract a day from the start_date of next month. :)
So write a custom method,
import datetime
def end_date_of_a_month(date):
start_date_of_this_month = date.replace(day=1)
month = start_date_of_this_month.month
year = start_date_of_this_month.year
if month == 12:
month = 1
year += 1
else:
month += 1
next_month_start_date = start_date_of_this_month.replace(month=month, year=year)
this_month_end_date = next_month_start_date - datetime.timedelta(days=1)
return this_month_end_date
Calling,
end_date_of_a_month(datetime.datetime.now().date())
It will return the end date of this month. Pass any date to this function. returns you the end date of that month.
This does not address the main question, but one nice trick to get the last weekday in a month is to use calendar.monthcalendar
, which returns a matrix of dates, organized with Monday as the first column through Sunday as the last.
# Some random date.
some_date = datetime.date(2012, 5, 23)
# Get last weekday
last_weekday = np.asarray(calendar.monthcalendar(some_date.year, some_date.month))[:,0:-2].ravel().max()
print last_weekday
31
The whole [0:-2]
thing is to shave off the weekend columns and throw them out. Dates that fall outside of the month are indicated by 0, so the max effectively ignores them.
The use of numpy.ravel
is not strictly necessary, but I hate relying on the mere convention that numpy.ndarray.max
will flatten the array if not told which axis to calculate over.
Use pandas!
def isMonthEnd(date):
return date + pd.offsets.MonthEnd(0) == date
isMonthEnd(datetime(1999, 12, 31))
True
isMonthEnd(pd.Timestamp(\'1999-12-31\'))
True
isMonthEnd(pd.Timestamp(1965, 1, 10))
False
I prefer this way
import datetime
import calendar
date=datetime.datetime.now()
month_end_date=datetime.datetime(date.year,date.month,1) + datetime.timedelta(days=calendar.monthrange(date.year,date.month)[1] - 1)
import calendar
from time import gmtime, strftime
calendar.monthrange(int(strftime(\"%Y\", gmtime())), int(strftime(\"%m\", gmtime())))[1]
Output:
31
This will print the last day of whatever the current month is. In this example it was 15th May, 2016. So your output may be different, however the output will be as many days that the current month is. Great if you want to check the last day of the month by running a daily cron job.
So:
import calendar
from time import gmtime, strftime
lastDay = calendar.monthrange(int(strftime(\"%Y\", gmtime())), int(strftime(\"%m\", gmtime())))[1]
today = strftime(\"%d\", gmtime())
lastDay == today
Output:
False
Unless it IS the last day of the month.
If you want to make your own small function, this is a good starting point:
def eomday(year, month):
\"\"\"returns the number of days in a given month\"\"\"
days_per_month = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
d = days_per_month[month - 1]
if month == 2 and (year % 4 == 0 and year % 100 != 0 or year % 400 == 0):
d = 29
return d
For this you have to know the rules for the leap years:
If you pass in a date range, you can use this:
def last_day_of_month(any_days):
res = []
for any_day in any_days:
nday = any_day.days_in_month -any_day.day
res.append(any_day + timedelta(days=nday))
return res
In the code below \'get_last_day_of_month(dt)\' will give you this, with date in string format like \'YYYY-MM-DD\'.
import datetime
def DateTime( d ):
return datetime.datetime.strptime( d, \'%Y-%m-%d\').date()
def RelativeDate( start, num_days ):
d = DateTime( start )
return str( d + datetime.timedelta( days = num_days ) )
def get_first_day_of_month( dt ):
return dt[:-2] + \'01\'
def get_last_day_of_month( dt ):
fd = get_first_day_of_month( dt )
fd_next_month = get_first_day_of_month( RelativeDate( fd, 31 ) )
return RelativeDate( fd_next_month, -1 )
Here is another answer. No extra packages required.
datetime.date(year + int(month/12), (month+1)%12, 1)-datetime.timdelta(days=1)
Get the first day of the next month and subtract a day from it.
you can use relativedelta
https://dateutil.readthedocs.io/en/stable/relativedelta.html
month_end = <your datetime value within the month> + relativedelta(day=31)
that will give you the last day.
Here is a solution based python lambdas:
next_month = lambda y, m, d: (y, m + 1, 1) if m + 1 < 13 else ( y+1 , 1, 1)
month_end = lambda dte: date( *next_month( *dte.timetuple()[:3] ) ) - timedelta(days=1)
The next_month
lambda finds the tuple representation of the first day of the next month, and rolls over to the next year. The month_end
lambda transforms a date (dte
) to a tuple, applies next_month
and creates a new date. Then the \"month\'s end\" is just the next month\'s first day minus timedelta(days=1)
.
I hope,It\'s usefull for very much..Try it on this way..we must need import some package
import time
from datetime import datetime, date
from datetime import timedelta
from dateutil import relativedelta
start_date = fields.Date(
string=\'Start Date\',
required=True,
)
end_date = fields.Date(
string=\'End Date\',
required=True,
)
_defaults = {
\'start_date\': lambda *a: time.strftime(\'%Y-%m-01\'),
\'end_date\': lambda *a: str(datetime.now() + relativedelta.relativedelta(months=+1, day=1, days=-1))[:10],
}
i have a simple solution:
import datetime
datetime.date(2012,2, 1).replace(day=1,month=datetime.date(2012,2,1).month+1)-timedelta(days=1)
datetime.date(2012, 2, 29)