# Getting the Nth Occurrence Of A Day Of The Week For A Given Month

Posted December 30, 2008 at 9:13 AM by Ben Nadel

Tags: ColdFusion

Yesterday, I was trying to determine when to turn on and off day light savings time for a given date calculation. Based on some Googling (cause I don't know this kind of stuff off-hand), it looks like day light savings time in this country goes from the second Sunday in March to the first Sunday of November. Because of this, I had to come up with a way to find the first and second sunday of a month.

Sunday happens to be a really easy day to find since it's always at the beginning of the week. This allowed me to create a simple formula based on the first day of the month:

FDOM + ((8 - DayOfWeek( FDOM )) % 7)

Note: FDOM = First Day Of Month

Once I was done with that, I decided to expand this idea. I created a ColdFusion user defined function that would allow me to get the Nth occurrence of any given day of the week for a given month (ex. the second Tuesday of the month - NYCFUG meeting!). The logic is a little more complex than the above equation since the day of the week is not predictable. However, it's still quite straightforward:

• <cffunction
• name="GetNthDayOfMonth"
• access="public"
• returntype="any"
• output="false"
• hint="I return the Nth instance of the given day of the week for the given month (ex. 2nd Sunday of the month).">
•
• <!--- Define arguments. --->
• <cfargument
• name="Month"
• type="date"
• required="true"
• hint="I am the month for which we are gathering date information."
• />
•
• <cfargument
• name="DayOfWeek"
• type="numeric"
• required="true"
• hint="I am the day of the week (1-7) that we are locating."
• />
•
• <cfargument
• name="Nth"
• type="numeric"
• required="false"
• default="1"
• hint="I am the Nth instance of the given day of the week for the given month."
• />
•
• <!--- Define the local scope. --->
• <cfset var LOCAL = {} />
•
• <!---
• First, we need to make sure that the date we were given
• was actually the first of the month.
• --->
• <cfset ARGUMENTS.Month = CreateDate(
• Year( ARGUMENTS.Month ),
• Month( ARGUMENTS.Month ),
• 1
• ) />
•
•
• <!---
• Now that we have the correct start date of the month, we
• need to find the first instance of the given day of the
• week.
• --->
• <cfif (DayOfWeek( ARGUMENTS.Month ) LTE ARGUMENTS.DayOfWeek)>
•
• <!---
• The first of the month falls on or before the first
• instance of our target day of the week. This means we
• won't have to leave the current week to hit the first
• instance.
• --->
• <cfset LOCAL.Date = (
• ARGUMENTS.Month +
• (ARGUMENTS.DayOfWeek - DayOfWeek( ARGUMENTS.Month ))
• ) />
•
• <cfelse>
•
• <!---
• The first of the month falls after the first instance
• of our target day of the week. This means we will
• have to move to the next week to hit the first target
• instance.
• --->
• <cfset LOCAL.Date = (
• ARGUMENTS.Month +
• (7 - DayOfWeek( ARGUMENTS.Month )) +
• ARGUMENTS.DayOfWeek
• ) />
•
• </cfif>
•
•
• <!---
• At this point, our Date is the first occurrence of our
• target day of the week. Now, we have to navigate to the
• target occurence.
• --->
• <cfset LOCAL.Date += (7 * (ARGUMENTS.Nth - 1)) />
•
• <!---
• Return the given date. There is a chance that this date
• will be in the NEXT month of someone put in an Nth value
• that was too large for the current month to handle.
• --->
• <cfreturn DateFormat( LOCAL.Date ) />
• </cffunction>

To test this, I gathered the first thee occurrences of each day of the week for this month (December 2008):

• <!--- Loop over each day of the week. --->
• <cfloop
• index="intDayOfWeek"
• from="1"
• to="7"
• step="1">
•
• <p>
• <strong>#DayOfWeekAsString( intDayOfWeek )#</strong><br />
•
• 1st: #GetNthDayOfMonth( Now(), intDayOfWeek, 1 )#<br />
• 2nd: #GetNthDayOfMonth( Now(), intDayOfWeek, 2 )#<br />
• 3rd: #GetNthDayOfMonth( Now(), intDayOfWeek, 3 )#<br />
• </p>
•
• </cfloop>

We really only need the first 2 occurences to test this since every subsequent occurence is gotten with the addition of a constant 7 days. And, since the number of days in a week is static, this will never fail if the 2nd occurrence is accurate. When we run this code, we get the following output:

Sunday
1st: 07-Dec-08
2nd: 14-Dec-08
3rd: 21-Dec-08

Monday
1st: 01-Dec-08
2nd: 08-Dec-08
3rd: 15-Dec-08

Tuesday
1st: 02-Dec-08
2nd: 09-Dec-08
3rd: 16-Dec-08

Wednesday
1st: 03-Dec-08
2nd: 10-Dec-08
3rd: 17-Dec-08

Thursday
1st: 04-Dec-08
2nd: 11-Dec-08
3rd: 18-Dec-08

Friday
1st: 05-Dec-08
2nd: 12-Dec-08
3rd: 19-Dec-08

Saturday
1st: 06-Dec-08
2nd: 13-Dec-08
3rd: 20-Dec-08

Based on the following calendar, this output appears to be accurate.

The name of the ColdFusion UDF might not be the best. I played around with GetNthDayOfWeekOfMonth() but that just felt so wordy. I guess it can always be changed later on.

### Looking For a New Job?

25% of job board revenue is donated to Kiva. Loans that change lives - Find out more »

Dec 30, 2008 at 10:53 AM // reply »

<cough><cough>cflib</cough></cough>

http://www.cflib.org/udf/GetNthOccOfDayInMonth

From 2001. ;)

Dec 30, 2008 at 10:57 AM // reply »

@Ray,

Ha ha :) That's too funny. I need to get more in the habit of looking stuff up. The methods are slightly different - mine returns an actual date, his returns a numeric day; but yeah, basically they are performing the same logic.

Dec 30, 2008 at 11:35 AM // reply »

One extra thing you may want to add is LAST (I just wrote a date utils for Flex that includes this...mine had an even weirder name dayOfWeekIterationOfMonth :) ). This gets the last occurrence of that day of the week for the month. A little easier in Flex to do this as you can assign a constant to that value, and have people pass in FlexDateUtils.LAST as the occurrence to get, but more logical than having to pass in 7 (for e.g.) to get the last occurrence of a day of the week.

Dec 30, 2008 at 11:38 AM // reply »

@Gareth,

Cool idea. I hadn't even thought of that, but I can easily see that being really useful. Thanks.

Dec 30, 2008 at 11:38 AM // reply »

CFLib ftw again: http://www.cflib.org/udf/GetLastOccOfDayInMonth

Dec 30, 2008 at 11:43 AM // reply »

Ha ha :)

Dec 30, 2008 at 1:40 PM // reply »

Bah. I say keep on coding before you look stuff up. Some might tell you that your time is worth more than that, but not me. Anything that stretches the brain is a good thing.

(But do look it up when you are done and make sure your solution doesn't completely suck, of course. To err is human.)

Dec 30, 2008 at 1:50 PM // reply »

@Rick,

I am in a like-mindset. It's fun to solve problems.

Dec 30, 2008 at 3:02 PM // reply »

@Rick: Yes, that. Absent a time constraint, I like poking around at a problem first. It's almost like homework, with the internet being the answers in the back of the book.

Of course, while many books are pretty solid, some can have sketchy solutions ... don't be afraid to question something if it doesn't match what you expected.

Dec 31, 2008 at 10:37 PM // reply »

You probably already know this, but when (and who observes) daylight time savings occurs changes over time (most recent change is just a couple of years old). Any algorithm would need to have an effective (start/end) date if were to be used over a long period of time.

Jan 1, 2009 at 12:05 AM // reply »

I didn't realize this was to account for DST (I finally read the whole post :) ). I actually wrote something to account for DST also. I made a DaylightSavingTimeUS class to handle the changes for the US.

I created a DSTStart method and DSTEnd method that accepts a date (or could be a year). These are the public methods, then I have 2 private methods that account for any differences in the DST prior to the current DST start and end. I called them 'DSTStartBefore2007' which is probably not the best name for them if/when they change in the future, but you get the idea :) Then whenever it changes, I just add the new changes to the "before" methods, and anyone calling the DSTStart or DSTEnd won't notice any difference.

I created my Flex version of this to try to calculate US Federal Holidays, which also need the "get X day of the week for X month".

Jan 5, 2009 at 8:37 AM // reply »

@Ronald,

Yeah, from what I was googling, it looks like the DST keeps changing. I am not sure how this time gets selected and from what I read briefly, it seemed rather arbitrary (decided by committee rather that a function of predictability). I guess I will need to readdress as needed.

@Gareth,

Way to factor out what changes :)

Jan 5, 2009 at 8:45 AM // reply »

As long as we're talking about it ... certainly DST for a global application is a pain, but even within the US there are challenges. Not everyone observes daylight saving time, and sometimes there are changes to that list that are not necessarily in sync with the changes to DST itself.

This is why you have the Indiana and Arizona time zones in Windows et al: currently only Arizona and Hawaii do not observe DST. Indiana began observing it in 2006. (My previous employer did a lot of phone surveys, so before 2006, we had semi-annual fun adjusting all appointments over the weekend and then explaining to our clients for the next month or so why our time was different.)

It's not a complication if you're displaying application time, but if you're trying to display local time, it can be tricky (which is why some apps simply ask for East/Central/Mountain/Pacific and DST on/off: fine for continental US, inadequate otherwise), and historical local time can be a nightmare.

Jan 5, 2009 at 8:54 AM // reply »

@Dave,

We have an app that needs to calculate time based on a given Zip code. We have a zip code look-up table which has a yes/no flag for whether or not they observe daylight savings time. We are just going off that to keep it simple. But, as mentioned above, I guess the delimiters for DST will have to be re-adjusted from year to year.

Jan 22, 2009 at 11:11 AM // reply »

I wrote this algorithm in PHP. It can probably pretty easily be converted to any language. Read the comments that I inserted in the code to get an idea of how the algorithm works.

This will give you any occurrence of a day of week. For example, the third Tuesday of the month, the last Friday of the month, the second Monday of the month? you get the picture.

\$DOW = day of the week (0 = Sunday, 6 = Saturday).
\$X = occurence (1 = first, 2 = third, etc..). If the given month does not have the occurrence, then it will return the last. For example, if you ask for the 7th occurrence of Friday, it will return the last Friday of the month.
\$M = month
\$Y = year

Example, get_Xth_DOW(2,3,7,2009) will return the third Tuesday of July 2009. It just returns the day. If you want the date you can just do
\$D = get_Xth_DOW(\$DOW,\$X,\$M,\$Y);
echo \$M . "/" . \$D . "/" . \$Y;

The algorithm (bottom of post) is quick and simple.

It first gets the first occurrence. It can then add multiples of 7 to get the Xth occurrence.

function get_Xth_DOW(\$DOW,\$X,\$M,\$Y) {
# Start at the first day of the month
\$d = 1;

# Get the day of week for the first day of the month
# date() returns 0 = Sunday, through 6 = Saturday
\$firstDOW = date('w',mktime(0,0,0,\$M,1,\$Y));

# Get the difference in the number of days between
# the dow of the first of the month and the dow that
# you are looking for.
\$DOW_offset = \$firstDOW - \$DOW;

# Adjust the date (d) to get to the first occurrence
if(\$DOW_offset > 0) { \$d += (7 - \$DOW_offset); }
else if (\$DOW_offset < 0) { \$d += -1*\$DOW_offset; }

# Add multiples of 7 to the first occurrence of the dow
# to get to the Xth occurrence

# If you went over the number of days in the month,
# then it is time to backtrack to the last occurrence
# of dow.
# numDays is the number of days in the current Month and Year
\$numDays = date('t',mktime(0,0,0,\$M,1,\$Y));
while(\$d > \$numDays) { \$d -= 7; }

# return the day.
return \$d;
}

Mar 10, 2009 at 2:34 PM // reply »

@Joe Dundas, thanks for your code. It's been very helpful to me. I'm working on a slight variation and I wonder if you have any ideas. What I'd like to do is determine what occurrence *today* is (e.g. today, March 10th, is the 2nd Tuesday of the month). So, I'd like to turn this logic around just a little bit and take today's day/date and return what nth occurrence it is in this month.

Ideas? Much appreciated.

Mar 10, 2009 at 2:56 PM // reply »

Hi John,

Take the ceiling of \$D/7. Where \$D is the day of the month.

For example,

for 2/11/2009.
\$D = 11;
\$occurrence = ceil(\$D/7) = ceil(1.57) = 2

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.

 Author Name: Author Email: Author Website: Comment: Supported HTML tags for formatting: bold   italic   code Remember my information Subscribe to comments Send me a copy of this comment
InVision App - Prototyping Made Beautiful With Prototyping Tools Recent Blog Comments
Mar 11, 2014 at 12:21 PM
Compound Transclusion Prevented In AngularJS 1.2
Yeah this hit our team too and locked us as 1.1.5. It seemed like an irresponsible unilateral decision, but our graver concern is the future decisions the Angular team will make with other fundamenta ... read »
Mar 11, 2014 at 2:00 AM
ColdFusion, jQuery, And "AJAX" File Upload Demo
Mar 10, 2014 at 8:24 PM
Nested Views, Routing, And Deep Linking With AngularJS
@Steven, the action property is not something from AngularJS but rather part of the concept that Ben is describing in his blogpost here. it is a custom added property, which is read by the requestCo ... read »
Mar 10, 2014 at 2:03 PM
Nested Views, Routing, And Deep Linking With AngularJS
Where is the angular documentation for 'action:' it is not here: http://docs.angularjs.org/api/ngRoute/provider/ \$routeProvider Thanks. ... read »
Mar 10, 2014 at 12:06 PM
Using Track-By With ngRepeat In AngularJS 1.2
I was hoping that this will work with pagination using ng-repeat. My use case scenario is that I have an images object. images[0] = [im1,im2,im3] // First Page images[1] = [im4, im5, im6] // Second ... read »
Mar 9, 2014 at 6:11 PM
For Better Security Use HtmlEditFormat() In Conjunction With JSStringFormat() In ColdFusion
It looks like htmleditformat() will be deprecated in CF 11 https://wikidocs.adobe.com/wiki/display/coldfusionen/New +in+ColdFusion ... read »
Mar 9, 2014 at 10:55 AM
\$.stop() vs. \$.finish() In jQuery Animations
Nice feature! Thanks for sharing. :) Good for when you are making a 100% AJAX controlled site. ... read »
Mar 9, 2014 at 12:26 AM
Experimenting With Multiple Class Inheritance In Javascript
@bigboomshakala, Hi, I am want present so solution for multiple prototypical inheritance, but some restrictions. Please follow the link: http://arto8.site11.com/ArtoJS/multi-inheritance-prototype.ph ... read »