I often do reporting that requires the first and last day of the month as bounds. I ended up writing repetitive code until I wrote these utility functions. You might find them useful too.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | #!/usr/bin/env python
import datetime
import time
def mkDateTime(dateString,strFormat="%Y-%m-%d"):
# Expects "YYYY-MM-DD" string
# returns a datetime object
eSeconds = time.mktime(time.strptime(dateString,strFormat))
return datetime.datetime.fromtimestamp(eSeconds)
def formatDate(dtDateTime,strFormat="%Y-%m-%d"):
# format a datetime object as YYYY-MM-DD string and return
return dtDateTime.strftime(strFormat)
def mkFirstOfMonth2(dtDateTime):
#what is the first day of the current month
ddays = int(dtDateTime.strftime("%d"))-1 #days to subtract to get to the 1st
delta = datetime.timedelta(days= ddays) #create a delta datetime object
return dtDateTime - delta #Subtract delta and return
def mkFirstOfMonth(dtDateTime):
#what is the first day of the current month
#format the year and month + 01 for the current datetime, then form it back
#into a datetime object
return mkDateTime(formatDate(dtDateTime,"%Y-%m-01"))
def mkLastOfMonth(dtDateTime):
dYear = dtDateTime.strftime("%Y") #get the year
dMonth = str(int(dtDateTime.strftime("%m"))%12+1)#get next month, watch rollover
dDay = "1" #first day of next month
nextMonth = mkDateTime("%s-%s-%s"%(dYear,dMonth,dDay))#make a datetime obj for 1st of next month
delta = datetime.timedelta(seconds=1) #create a delta of 1 second
return nextMonth - delta #subtract from nextMonth and return
if __name__=="__main__":
for i in range(12):
thisMonth = ("0%i"%(i+1,))[-2:]
print thisMonth
d = mkDateTime("2004-%s-02"%thisMonth)
print formatDate(d)
print formatDate(d,"%Y%m%d")
print mkFirstOfMonth(d)
print mkFirstOfMonth2(d)
print mkLastOfMonth(d)
|
Often I need to know the last day of the month and the first. It is a simple thing to calc the first of the month since it is fixed, however the last day of the month is a bit more interesting.
In this, I calc the first day of the next month by incrementing the current month by 1, account for rollover. Then I subtract 1 second and there you are.
You will note that mkFirstOfMonth and mkFirstOfMonth2 do the same thing yet in different ways. mkFirstDayOfMonth is a hack while mkFirstOfMonth2 is, in my opinion, more pythonic.
strftime? No need for all the strftime work, since date and datetime objects have attributes representing their days, months, years, etc.
For comparison, here's another way to write first_day and last_day functions. It's a bit opaque and undocumented, but is likely faster.
The get_first_day function is a bit more convoluted than is stricly necessary. But allowing for those delta_month and delta_year optional arguments allows for a simpler get_last_month function, as well as letting you, e.g., get the last day of this month in the previous year.
thisMonth = ("0%i"%(i+1,))[-2:]. There's an easier way to do this:
The '02' qualifier means, "make it two characters wide, and pad it with zeroes on the left if necessary".
You might also use "range(1, 13)" instead of "range(12)", then you wouldn't have to add the one every time.
Alternative: use dateutil from labix.org. This library offers a relativedelta type. Adding relativedelta(day=31) to a date allways gives you the last day of the month that date is in.
You can do way more with this library, if you work a lot with dates it's worth a look.
Number of days in months for year 2006 --- calendar module. >>> [calendar.monthrange(year,month)[1] for year in [2006] for month in range(1,13)]
Results in:
[31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
it doesn't work. How about today is 2007-12-30? It will give next month as 2007-01-01.
A quick fix to that problem. thx for useful code, i added a little hax to make it work for e.g. 2004/12/01:
Sorry... I ment 1 instead of 12:
For the specific problem of finding the last day of a month, I use:
... which is a bit shorter.
All the presented solutions use some sort of hacks: incrementing month without incrementing year, check for month changing "12 -> 01" etc.
I present slower but simpler solution: we sequentially increment date passed into function until month changes, then get day-of-month from previous value:
Hello ,
Please forgive me if I have misunderstood the question/issue , I have just started learning Python and programming in general.
If I wanted to find the last day of any month I would use the calender.monthrange(year,month) function ( as described in python docs):
This function returns a tuple , element zero [0] is the weekday of the first day , the example below uses February 2004 , the first day was a Saturday, therefore lastday1[0]=6.
Element one [1] returns the number of days in month. therefore lastday1[1]=29. Note that 2004 was a leapyear.
For demonstration sake I have used the result in a datetime function. Please see Python interactive session below .
Link: calendar module
Oops !
Weekday numbers start from 0 with default first day as Monday , therefore a weekday of 6 refers to Sunday not Saturday as described above .
The first day of February 2004 is a Sunday.
Let's update this one a little: monthrange(year, month) Returns weekday of first day of the month and number of days in month, for the specified year and month.