Ask Ben: Finding The Last Monday Of The Month In ColdFusion

Posted July 31, 2007 at 9:22 AM by Ben Nadel

Tags: ColdFusion, Ask Ben

I see that you have been doing a lot of calendar stuff lately and I have question. How can I find the last monday of the month? TIA!

Finding the last monday of the month, or last "whatever" day of the week, just takes a little bit of math. Basically, what you want to do is get the last week of the month. This we can easily do by finding the last day of the month (first day of next month minus one day). From the last day, we can get the last week. Then, from the last week we can get the day of the week we are looking for. Of course, there is nothing about the day, at that point, that requires it to be in the current month. Therefore, all we need to do is compare the month of that day to the month we are looking at. If they are the same, we have our "last day"; if they are different, then by subtracting a week from that day, we will have found our "last day".

That's a bit of a mouthful; it might just be easier to walk through the code:

  • <!--- Get the current month based on the curren date. --->
  • <cfset dtThisMonth = CreateDate(
  • Year( Now() ),
  • Month( Now() ),
  • 1
  • ) />
  •  
  • <!---
  • Now, get the last day of the current month. We
  • can get this by subtracting 1 from the first day
  • of the next month.
  • --->
  • <cfset dtLastDay = (
  • DateAdd( "m", 1, dtThisMonth ) -
  • 1
  • ) />
  •  
  • <!---
  • Now, the last day of the month is part of the last
  • week of the month. However, there is no guarantee
  • that the "Monday" of this week will be in the current
  • month. If Sunday was the last day of the month, then
  • Monday would be the first day of the next month.
  • Regardless, let's get the date of the target day.
  • --->
  • <cfset dtMonday = (
  • dtLastDay -
  • DayOfWeek( dtLastDay ) +
  •  
  • <!---
  • This is the day of the week that we are
  • trying to find (2 = Monday).
  • --->
  • 2
  • ) />
  •  
  •  
  • <!---
  • Now, we have a Monday, but we are not exactly sure if
  • this Monday is in the current month. if is not, then
  • we know it is the first Monday of the next month, in
  • which case, subracting 7 days (one week) from it will
  • give us the last Monday of the current Month.
  • --->
  • <cfif (Month( dtMonday ) NEQ Month( dtThisMonth ))>
  •  
  • <!--- Subract a week. --->
  • <cfset dtMonday = (dtMonday - 7) />
  •  
  • </cfif>
  •  
  •  
  • <!---
  • Output the date of the last Monday. CAUTION: Our date
  • math above has left us with a NUMERIC DATE, not a
  • traditional date/time stamp. Therefore, be careful
  • about using things like IsDate() as this numeric date
  • will NOT pass these checks.
  • --->
  • <p>
  • Last Monday Of Month:
  • #DateFormat( dtMonday, "full" )#
  • </p>

Running the above code we get the following output:

Last Monday Of Month: Monday, July 30, 2007

Now, we just found the last Monday, but we could easily abstract this out to find any "last day" of the month. Notice that in the above algorithm, we only referred to Monday as being day "2" in one place. By replacing that "2" with a variable, suddenly, we can find any last day of the week - of the month.

Let's wrap that up in a ColdFusion user defined function, GetLastDayOfWeekOfMonth(). I know that function name is a mouthful, but frankly, I couldn't come up with anything better to call it:

  • <cffunction
  • name="GetLastDayOfWeekOfMonth"
  • access="public"
  • returntype="date"
  • output="false"
  • hint="Returns the date of the last given weekday of the given month.">
  •  
  • <!--- Define arguments. --->
  • <cfargument
  • name="Date"
  • type="date"
  • required="true"
  • hint="Any date in the given month we are going to be looking at."
  • />
  •  
  • <cfargument
  • name="DayOfWeek"
  • type="numeric"
  • required="true"
  • hint="The day of the week of which we want to find the last monthly occurence."
  • />
  •  
  • <!--- Define the local scope. --->
  • <cfset var LOCAL = StructNew() />
  •  
  • <!--- Get the current month based on the given date. --->
  • <cfset LOCAL.ThisMonth = CreateDate(
  • Year( ARGUMENTS.Date ),
  • Month( ARGUMENTS.Date ),
  • 1
  • ) />
  •  
  • <!---
  • Now, get the last day of the current month. We
  • can get this by subtracting 1 from the first day
  • of the next month.
  • --->
  • <cfset LOCAL.LastDay = (
  • DateAdd( "m", 1, LOCAL.ThisMonth ) -
  • 1
  • ) />
  •  
  • <!---
  • Now, the last day of the month is part of the last
  • week of the month. However, there is no guarantee
  • that the target day of this week will be in the current
  • month. Regardless, let's get the date of the target day
  • so that at least we have something to work with.
  • --->
  • <cfset LOCAL.Day = (
  • LOCAL.LastDay -
  • DayOfWeek( LOCAL.LastDay ) +
  • ARGUMENTS.DayOfWeek
  • ) />
  •  
  •  
  • <!---
  • Now, we have the target date, but we are not exactly
  • sure if the target date is in the current month. if
  • is not, then we know it is the first of that type of
  • the next month, in which case, subracting 7 days (one
  • week) from it will give us the last occurence of it in
  • the current Month.
  • --->
  • <cfif (Month( LOCAL.Day ) NEQ Month( LOCAL.ThisMonth ))>
  •  
  • <!--- Subract a week. --->
  • <cfset LOCAL.Day = (LOCAL.Day - 7) />
  •  
  • </cfif>
  •  
  •  
  • <!--- Return the given day. --->
  • <cfreturn DateFormat( LOCAL.Day ) />
  • </cffunction>

Now that we have that in place, let's run a little script to test it out across the year:

  • <p>
  • <!--- Loop over every month in year. --->
  • <cfloop
  • index="intMonth"
  • from="1"
  • to="12"
  • step="1">
  •  
  • <!--- Get last monday. --->
  • #GetLastDayOfWeekOfMonth(
  • "#intMonth#/1/2007",
  • 2
  • )#<br />
  •  
  • </cfloop>
  • </p>

Running that code, we get the following output:

29-Jan-07
26-Feb-07
26-Mar-07
30-Apr-07
28-May-07
25-Jun-07
30-Jul-07
27-Aug-07
24-Sep-07
29-Oct-07
26-Nov-07
31-Dec-07

Notice that our July 30, 2007 lines up with our first example. And, checking my calendar, the rest of the dates line up nicely.




Reader Comments

Jul 31, 2007 at 10:26 AM // reply »
18 Comments

The problem with the numeric date due to your date math, could you get round this by just using DateAdd functions instead of doing arithmetic directly on the date object?


Jul 31, 2007 at 11:29 AM // reply »
11,243 Comments

@Duncan,

Yes, DateAdd() would get around the formatting issue, however, I am pretty sure that doing date math directly is faster than calling the DateAdd(). Plus, and this is just my personal preference, doing math looks nicer. DateAdd(), to me, adds a lot of "noise" to the code that really isn't adding any benefit (of course, that is only true if you know that you can do date math).... but again, mostly personal preference.


Aug 2, 2007 at 1:36 PM // reply »
3 Comments

i thought of another interesting way to accomplish the same thing, which was a little more intuitive for me. instead of just subtracting one week if the day that you originally selected happens to fall in the next month, you simply loop "backwards" from the last day of the month by subtracting zero through six from it until you find the day you are looking for. if you were looking for the last sunday, and sunday happens to be the last day of the month, you're golden. otherwise you just work backwards saturday, friday, etc. until you hit your target day.


Aug 5, 2007 at 5:16 PM // reply »
11,243 Comments

@Sherrardb,

Yes, that would accomplish the same thing, so if you find that method more intuitive, by all means go for it.


Aug 7, 2007 at 12:39 AM // reply »
2 Comments

Thanks Ben, Great solution. You saved me from having to think too hard ;)


May 15, 2009 at 11:20 AM // reply »
3 Comments

Thanks a lot, this last day of the month methodology helped me get something done I needed to do very quickly. You rock!


May 19, 2009 at 9:32 AM // reply »
11,243 Comments

@Curtis,

Glad to help!


Aug 25, 2009 at 8:14 PM // reply »
1 Comments

Thank you for sharing, Ben. Really learned a great deal!


Sep 6, 2009 at 1:04 PM // reply »
11,243 Comments

@Guido,

My pleasure.


Jun 12, 2010 at 8:43 AM // reply »
1 Comments

how to find on which day of the week the last day of the month falls on


Jun 14, 2010 at 10:49 PM // reply »
11,243 Comments

@Ramya,

For something like that, I'd probably just get the first day of the next month, subtract one, and then use dayOfWeek().


Feb 2, 2011 at 7:00 PM // reply »
1 Comments

Ben,

You Rock!

That is all.

-Brad


Feb 27, 2013 at 8:37 AM // reply »
1 Comments

You can find the last day of any month with just 3 lines of CF code:

<cfset Variables.monthEnd = DateFormat(DateAdd("m",1, Now()), "mm/d/yyyy")>
<cfset Variables.monthEnd = ListSetAt(Variables.monthEnd,2,"1","/")>
<cfset Variables.monthEnd = DateFormat(DateAdd("d",-1, Variables.monthEnd), "mm/d/yyyy")>



Post A Comment

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
May 23, 2013 at 11:06 AM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@Ben, Are you talking about As Number: YES As String: YES As Java: YES? If so, that's with 3 different ways of referencing the constant 1, not users.id[1]. Query object references(*) are what seem ... read »
May 23, 2013 at 9:55 AM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@Dan, According to the CF Admin, I'm running Java "1.6.0_45". As far as the DB column, in the database it's an INT. I'll see if I can dig into what CF sees it as. @WebManWalking, But h ... read »
May 23, 2013 at 9:49 AM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@Ben, I think the problem is that we're used to loose typing in ColdFusion, like JavaScript. If a value is a number but it's needed in an expression to be a string, noooo problem. I've encountered ... read »
May 23, 2013 at 9:47 AM
ColdFusion QueryAppend( qOne, qTwo )
You rock! Thank you, thank you, thank you!!! ... read »
May 23, 2013 at 5:19 AM
Ask Ben: Print Part Of A Web Page With jQuery
How to print also the background color of table cells and table lines ... read »
May 23, 2013 at 3:55 AM
Javascript Array Methods: Unshift(), Shift(), Push(), And Pop()
very interesting and helpful too. ... read »
May 22, 2013 at 5:35 PM
Script Tags, jQuery, And Html(), Text() And Contents()
This is still an issue 2 years later. jQuery is supposed to remediate these cross browser issues, no? I have been unable to find any statement from the jQuery team calling this behavior "by de ... read »
May 22, 2013 at 12:44 PM
Ask Ben: Query Loop Inside CFScript Tags
In cf10, if you call a function that has: local.result = {}; local.result.msg = ""; local.svc = new query(); local.svc.setSQL("SELECT * FROM..."); local.obj = local.svc.exe ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools