how to get the last day of a given month??

Help my friends,

Again I am banging my head for hours…

It is very simple in old AppleScript, but ASOC is not…

I wonder if someone could help me get the last day of a given month in ASOC.


The trick in all programming languages is the first day of next month - 24 hours

Thanks DJ.

I am really looking for some nice lines of code.

I can’t do thing in the old way such as:

date(current date) + (32 * days)

Any help?


Why can’t you? In my latest app, I used date stuff and it worked perfectly.

set theDate to (current date)
set newDate to theDate + (32 * days)

Now newDate is the date you were looking for.

Really? I cut and pasted your code, and I got a date that is 32 days from now – 9/19/2011.

One way that worked for me was :

set inputFormatter to current application's NSDateFormatter's alloc()'s init()
		inputFormatter's setDateFormat_("MM/yy")
		set theDate to inputFormatter's dateFromString_("09/11")
		set lastDay to theDate's dateByAddingTimeInterval_(-86400)
		log lastDay -- gives last day of August

That’s a cocoa way to do it. An applescript way is :

set theDate to date "9/1/11"
		set newDate to theDate - (1 * days)
		log newDate as string

This is before compiling. When you compile the “9/1/11” will be changed to “Thursday, September 1, 2011 12:00:00 AM”. NewDate should give you the last day of August.


Nonono. That was just an example. I was just reminding him that newDate is the variable containing the result of the date procedure. Now I’m just confusing myself… :slight_smile:

Anyway, it was an example.

This is it:

on clickTheButton_(sender)
    end clickTheButton_
    on GetLastDayOfMonth_(theMonth)
        (*** let's start with today: ***)
        set theDate to current date
        set month of theDate to theMonth
        log "theDate: " & theDate
        set newDate to theDate + (32 * days)
        log "newDate step 1: " & newDate as string
        set day of newDate to 1
        log "newDate step 2: " & newDate as string
        set newDate to newdate - (1 * days)
        log "newDate step 3: " & newDate
        set d to day of newDate
        log "d is: " & d 
        if d < 10 then set theDay to "0" & d 
        set m to month of newDate
        set m to m as number
        if m < 10 then set m to ("0" & m) as string 
        log "m is: " & m 
        set y to year of newDate
        log "y is : " & y 
        log "last day of month is: "&  d & "." & m & "." & y 
        return d & "." & m & "." & y 
    end GetLastDayOfMonth_

I don’t think this method will work if the current date is near the end of the month (you can test this by replacing the “set theDate to current date” line with – set theDate to date “8/30/11” – and try passing 2 to the method).

If you want to get the last day of a particular month in the current year by passing the month number to it, I think this will work:

on clickTheButton_(sender)
end clickTheButton_

on GetLastDayOfMonth_(theMonth)
		if theMonth = 12 then
			set dateString to "01/01/" & ((year of the (current date)) + 1 as string)
			set dateString to ((theMonth + 1) as string) & "/01/" & (year of the (current date) as string)
		end if
		set inputFormatter to current application's NSDateFormatter's alloc()'s init()
		inputFormatter's setDateFormat_("MM/dd/yy")
		set theDate to inputFormatter's dateFromString_(dateString)
		set lastDay to theDate's dateByAddingTimeInterval_(-86400)
		set outputFormatter to current application's NSDateFormatter's alloc()'s init()
		outputFormatter's setDateFormat_("dd/MM/yy")
		log outputFormatter's stringFromDate_(lastDay)
	end GetLastDayOfMonth_

Using a formatter for the output lets you format the date however you want in a more elegant way than using applescript methods (in my opinion).

A shorter and all applescript way to do it is with a list:

on GetLastDayOfMonth_(theMonth)
		set theYear to the year of the (current date)
		if (theYear - 2000) mod 4 = 0 and theMonth = 2 then set theMonth to 13
		set theList to {"31/01/", "28/02/", "31/03/", "30/04/", "31/05/", "30/06/", "31/07/", "31/08/", "30/09/", "31/10/", "30/11/", "31/12/", "29/02/"}
		set lastDay to (item theMonth of the theList) & theYear
		log lastDay
	end GetLastDayOfMonth_



this is a pure Cocoa/ASOC solution

	property NSDate : class "NSDate"
	property NSCalendar : class "NSCalendar"
	property NSDateComponents : class "NSDateComponents"

	on lastDayOfMonth_(theMonth) -- returns a date object
		set currentDate to NSDate's |date|
		set calendar to NSCalendar's currentCalendar
		-- the constant 12 is the equivalent to NSYearCalendarUnit|NSMonthCalendarUnit
		set components to calendar's components_fromDate_(12, currentDate)
		components's setMonth_(theMonth +1)
		components's setDay_(0)
		return  calendar's dateFromComponents_(components) 
	end lastDayOfMonth

I think eventually I will have to go all cocoa…

Sorry for late reply. But Stefan’s post is what I meant.

Many thanks to all of you my friends.


One last request please:

How do I convert the result into string?


If your local string representation is sufficient, call the description method of the date object.
If you need a special format, use NSDateFormatter


  components's setDay_(0)

Is the fact that setting the day to 0, takes you back to the last day of the previous month documented somewhere? I didn’t see that in the docs anywhere.


From the Date and Time Programming Guide:
In a calendar, day, week, weekday, month, and year numbers are generally 1-based

The class of the parameter for setDay: is NSInteger, therefore negative numbers might be valid.

I conclude, that setting the day to 0 means t - 1 day

But that doesn’t seem to be what’s happening – if you change your 12 to 28 in this line: set components to calendar’s components_fromDate_(12, currentDate), that includes the NSDayCalendarUnit. Now, if you log the dateFromComponents before setting the day to 0, you will get <month+1>/19/2011. But setting the day to 0 still gives you the last day of the month before. So, it looks like it is more than t-1 day.


Of course, setting the day to 0 changes the value of the day component anyway regardless of the previous state.
Omitting the NSDayCalendarUnit mask sets the day component to 1