August 19, 2009

Intention Revealing Code

I just watched the video of Robert Martin’s Norwegian Developers Conference presentation titled “Clean Code III - Functions”. In his hour-long talk, he talks about methods you can use and principles you should follow to make your code more understandable and more readable. He also show some sample code that is difficult to understand at first reading, and then some refactorings of that code that increase its understandability.

I won’t go into the details of his talk; you should watch it yourself. It’s well worth the hour-long investment. But his refactoring example reminded me of a refactoring exercise that I recently did.



The code in question is a class that provides date-based services such as calculating X number of business days before or after a given date, and determining whether a specific calendar date is a business date or a holiday. To do so, the service must follow these rules for determining holidays:
  • Independence Day, July 4
  • Labor Day, first Monday in September
  • Thanksgiving Day, fourth Thursday in November
  • Day after Thanksgiving Day, fourth Friday in November
  • Christmas Day, December 25
  • New Year's Day, January 1
  • Martin Luther King, Jr. Day, third Monday in January
  • President's Day, third Monday in February
  • Memorial Day, last Monday in May
Holidays falling on Saturday will be observed on Friday and holidays falling on Sunday will be observed on Monday.
We’ve got nine holidays, some determined by a particular position within a month (i.e. “fourth Thursday in November”), and some determined by a particular calendar date (i.e. “July 4th”). The holidays determined by calendar date may need to be adjusted by a day if the date falls on a weekend. The list of holidays is static; it’s not likely to change anytime soon.

The basic interface of the class is:

namespace Your.Namespace.Here

{

public interface IDateService

{

DateTime CalculatePriorBusinessDate(DateTime startDate, int numberOfBusinessDays);

DateTime CalculateSubsequentBusinessDate(DateTime startDate, int numberOfBusinessDays);

bool IsBusinessDate(DateTime calendarDate);

bool IsHolidayDate(DateTime calendarDate);
}
}
 
The implementation of the class is about 270 lines of code, including comments. You know how I feel about comments. Subtract them out, and you’re left with about 230 lines.

   1: namespace Your.Namespace.Here

   2: {

   3:     public class  DateService : IDateService

   4:     {

   5:         private string error = string.Empty;

   6:  

   7:         public DateService()

   8:         {

   9:         }

  10:  

  11:         /// <summary>

  12:         ///  Determines if a calendar date is a valid business date.

  13:         /// </summary>

  14:         /// <param name="calendarDate">This is any calendar date</param>

  15:         /// <returns>returns true, if calendar date is a valid business date, else returns false</returns>

  16:         /// 

  17:         public bool IsBusinessDate(DateTime calendarDate)

  18:         {

  19:             bool isBusinessDate = false;

  20:             // Weekends and Holidays are not business days

  21:             if (IsWeekend(calendarDate) || IsHoliday(calendarDate))

  22:             {

  23:                 isBusinessDate = false;

  24:             }

  25:             else

  26:                 isBusinessDate = true;

  27:             return isBusinessDate;

  28:         }

  29:  

  30:         /// <summary>

  31:         ///  Determines if a calendar date is a valid Holiday.

  32:         /// </summary>

  33:         /// <param name="calendarDate">This is any calendar date</param>

  34:         /// <returns>returns true, if calendar date is a valid holiday, else returns false</returns>

  35:         /// 

  36:         public bool IsHolidayDate(DateTime calendarDate)

  37:         {

  38:             bool isHolidayDate = false;

  39:  

  40:             if (IsHoliday(calendarDate))

  41:             {

  42:                 isHolidayDate = false;

  43:             }

  44:             else

  45:                 isHolidayDate = true;

  46:             return isHolidayDate;

  47:         }

  48:  

  49:         /// <summary>

  50:         /// Calculates prior business date 

  51:         /// </summary>

  52:         /// <param name="startDate">This is the starting business date to calculate</param>

  53:         /// <param name="numberOfBusinessDays">This is the number of prior business days requested;Must be positive integer</param>

  54:         /// <returns>The calculated business date requested based on number of business days</returns>

  55:         /// 

  56:         public DateTime CalculatePriorBusinessDate(DateTime startDate, int numberOfBusinessDays)

  57:         {

  58:             if (numberOfBusinessDays < 0)

  59:             {

  60:                 error = "Prior Business Days must be a positive number";

  61:                 throw new Exception(string.Format("reason : {0}", error));

  62:             }

  63:             return CalculateBusinessDate(startDate, numberOfBusinessDays * -1);

  64:         }

  65:  

  66:         /// <summary>

  67:         /// Calculates subsequent business date 

  68:         /// </summary>

  69:         /// <param name="startDate">This is the starting business date to calculate</param>

  70:         /// <param name="numberOfBusinessDays">This is the number of subsequent business days requested;Must be positive integer</param>

  71:         /// <returns>The calculated business date requested based on number of business days</returns>

  72:         /// 

  73:         public DateTime CalculateSubsequentBusinessDate(DateTime startDate, int numberOfBusinessDays)

  74:         {

  75:             if (numberOfBusinessDays < 0)

  76:             {

  77:                 error = "Subsequent Business Days must be a positive number";

  78:                 throw new Exception(string.Format("reason : {0}", error));

  79:             }

  80:             return CalculateBusinessDate(startDate, numberOfBusinessDays);

  81:         }

  82:  

  83:         private DateTime CalculateBusinessDate(DateTime startDate, int numberOfDays)

  84:         {

  85:             int busDays = 0;

  86:             DateTime curDate = startDate;

  87:             int incr = 1;

  88:             if (numberOfDays < 0)

  89:                 incr = -1;

  90:             while (busDays < Math.Abs(numberOfDays))

  91:             {

  92:                 curDate = curDate.AddDays(incr);

  93:  

  94:                 // Weekends and Holidays are not business days

  95:                 if (IsWeekend(curDate) || IsHoliday(curDate))

  96:                 { }

  97:                 else

  98:                     busDays = busDays + 1;

  99:             }

 100:             return curDate;

 101:         }

 102:  

 103:         private bool IsWeekend(DateTime curDate)

 104:         {

 105:             bool isOnWeekend = false;

 106:  

 107:             //Check for weekend date

 108:  

 109:             if (curDate.DayOfWeek == DayOfWeek.Saturday || curDate.DayOfWeek == DayOfWeek.Sunday)

 110:                 isOnWeekend = true;

 111:  

 112:             return isOnWeekend;

 113:         }

 114:  

 115:         private bool IsHoliday(DateTime curDate)

 116:         {

 117:             bool returnValue = false;

 118:  

 119:             // Check for New Year's, Christmas, and Independence Day

 120:  

 121:             if (curDate.Month == 1 && curDate.Day == 1)

 122:                 returnValue = true;

 123:             if (curDate.Month == 7 && curDate.Day == 4)

 124:                 returnValue = true;

 125:             if (curDate.Month == 12 && curDate.Day == 25)

 126:                 returnValue = true;

 127:  

 128:             // Friday is a holiday if actual holiday falls on Saturday

 129:  

 130:             if (curDate.DayOfWeek == DayOfWeek.Friday)

 131:             {

 132:                 if (curDate.Month == 12 && curDate.Day == 31)

 133:                     returnValue = true;

 134:                 if (curDate.Month == 7 && curDate.Day == 3)

 135:                     returnValue = true;

 136:                 if (curDate.Month == 12 && curDate.Day == 24)

 137:                     returnValue = true;

 138:             }

 139:  

 140:             // Monday is a holiday if actual holiday falls on Sunday

 141:  

 142:             if (curDate.DayOfWeek == DayOfWeek.Monday)

 143:             {

 144:                 if (curDate.Month == 1 && curDate.Day == 2)

 145:                     returnValue = true;

 146:                 if (curDate.Month == 7 && curDate.Day == 5)

 147:                     returnValue = true;

 148:                 if (curDate.Month == 12 && curDate.Day == 26)

 149:                     returnValue = true;

 150:             }

 151:  

 152:             // Test for Monday Holidays

 153:  

 154:             if (curDate.DayOfWeek == DayOfWeek.Monday)

 155:             {

 156:                 if (curDate.Month == 1 && WhichMonday(curDate) == 3)

 157:                     returnValue = true;

 158:                 if (curDate.Month == 2 && WhichMonday(curDate) == 3)

 159:                     returnValue = true;

 160:                 if (curDate.Month == 9 && WhichMonday(curDate) == 1)

 161:                     returnValue = true;

 162:                 if (curDate.Month == 5 && LastMondayInMay(curDate) == true)

 163:                     returnValue = true;

 164:             }

 165:  

 166:             // Test for Thanksgiving

 167:  

 168:             if (curDate.DayOfWeek == DayOfWeek.Thursday)

 169:             {

 170:                 if (curDate.Month == 11 && WhichThursday(curDate) == 4)

 171:                     returnValue = true;

 172:             }

 173:             // Test for Friday after Thanksgiving

 174:  

 175:             if (curDate.DayOfWeek == DayOfWeek.Friday)

 176:             {

 177:                 if (curDate.Month == 11 && WhichFriday(curDate) == 4)

 178:                     returnValue = true;

 179:             }

 180:             return returnValue;

 181:         }

 182:  

 183:         private int WhichMonday(DateTime curDate)

 184:         {

 185:             return WhichDay(curDate, DayOfWeek.Monday);

 186:         }

 187:  

 188:         private int WhichDay(DateTime curDate, DayOfWeek day)

 189:         {

 190:             int which = 0;

 191:             DateTime firstDay = GetFirstDay(curDate, day);

 192:             while (firstDay <= curDate)

 193:             {

 194:                 which += 1;

 195:                 if (curDate == firstDay)

 196:                     break;

 197:                 firstDay = firstDay.AddDays(7);

 198:                 if (firstDay.Month != curDate.Month)

 199:                 {

 200:                     throw new Exception("WhichDayError");

 201:                 }

 202:             }

 203:             return which;

 204:         }

 205:  

 206:         private DateTime GetFirstMonday(DateTime curDate)

 207:         {

 208:             return GetFirstDay(curDate, DayOfWeek.Monday);

 209:         }

 210:  

 211:         private DateTime GetLastMonday(DateTime curDate)

 212:         {

 213:             return GetLastDay(curDate, DayOfWeek.Monday);

 214:         }

 215:  

 216:         private DateTime GetFirstDay(DateTime curDate, DayOfWeek day)

 217:         {

 218:             DateTime myDate = new DateTime(curDate.Year, curDate.Month, 1);

 219:             while (myDate.DayOfWeek != day)

 220:             {

 221:                 myDate = myDate.AddDays(1);

 222:             }

 223:             return myDate;

 224:         }

 225:  

 226:         private DateTime GetLastDay(DateTime curDate, DayOfWeek day)

 227:         {

 228:             DateTime myDateTemp = curDate.AddMonths(1);

 229:             DateTime myDate = new DateTime(myDateTemp.Year, myDateTemp.Month, 1);

 230:             myDate = myDate.AddDays(-1);

 231:             while (myDate.DayOfWeek != day)

 232:             {

 233:                 myDate = myDate.AddDays(-1);

 234:             }

 235:             return myDate;

 236:         }

 237:  

 238:         private bool LastMondayInMay(DateTime curDate)

 239:         {

 240:             bool rv = false;

 241:             DateTime curMonday = GetLastMonday(curDate);

 242:             if (curMonday == curDate)

 243:                 rv = true;

 244:             return rv;

 245:         }

 246:  

 247:         private int WhichThursday(DateTime curDate)

 248:         {

 249:             return WhichDay(curDate, DayOfWeek.Thursday);

 250:         }

 251:  

 252:         private DateTime GetFirstThursday(DateTime curDate)

 253:         {

 254:             return GetFirstDay(curDate, DayOfWeek.Thursday);

 255:         }

 256:  

 257:         private int WhichFriday(DateTime curDate)

 258:         {

 259:             return WhichDay(curDate, DayOfWeek.Friday);

 260:         }

 261:  

 262:         private DateTime GetFirstFriday(DateTime curDate)

 263:         {

 264:             DateTime myDate = new DateTime(curDate.Year, curDate.Month, 1);

 265:             while (myDate.DayOfWeek != DayOfWeek.Friday)

 266:             {

 267:                 myDate = myDate.AddDays(1);

 268:             }

 269:             return myDate;

 270:         }

 271:     }

 272: }
 
Functionally, this code is fine. It meets all of the requirements, can correctly determine if a particular calendar date is a holiday, can correctly determine a previous or subsequent business date. But… It’s not very readable. By that I mean, can we read through the code and, at a glance, determine the rules it’s implementing? Can we see that Labor Day is accounted for? Can we tell that Saturday holidays are shifted to Friday? Not without mentally debugging it, line by line. The intent of the code (to meet the holiday calculation rules) is not revealed by reading the code. You’re left to figure it out yourself.

Some of the code loses readability by being too verbose. Take, for instance, the method used to determine if a particular date is a business date:

public bool IsBusinessDate(DateTime calendarDate)

{

bool isBusinessDate = false;

// Weekends and Holidays are not business days

if (IsWeekend(calendarDate) || IsHoliday(calendarDate))

{

isBusinessDate = false;

}

else

isBusinessDate = true;

return isBusinessDate;

}
 
That’s 11 lines of code (and one in-line comment) to express what could be expressed in one:

public bool IsBusinessDate(DateTime date)

{

return !IsWeekend(date) && !IsHoliday(date);

}
 
Not a weekend and not a holiday. Done. Smaller is not always better, but in this case I think it makes the code more precise and expressive while also minimizing the potential for a bugs to creep in.

Additionally, read through this block in the middle of the IsHoliday() method:

if (curDate.DayOfWeek == DayOfWeek.Monday)

{

if (curDate.Month == 1 && WhichMonday(curDate) == 3)

returnValue = true;

if (curDate.Month == 2 && WhichMonday(curDate) == 3)

returnValue = true;

if (curDate.Month == 9 && WhichMonday(curDate) == 1)

returnValue = true;

if (curDate.Month == 5 && LastMondayInMay(curDate) == true)

returnValue = true;

}
 
It is not immediately obvious what’s going on here. If you have the holidays memorized, you can tell that we’re checking for Martin Luther King, Jr. Day, Memorial Day, and a few other Monday holidays. But you have to stop and think about it, doing the mental calendar math to determine which holidays we’re dealing with. It would be better if the code expressed this explicitly.

Taking a step back


Before starting any refactoring, a decided to take a step back and think about how I would go about determining if a date was a holiday. The most straightforward way is to get a list of holidays, and then check my date against that list. That list of holidays must include the nine holidays listed in the rules above, adjusted for weekends if necessary.

I began the refactoring with that process in mind. To start with, I would need to generate the holiday list for the given year. So, I created a method to do so:

public IList<DateTime> HolidaysForYear(int year)

{

var holidayList = new List<DateTime>();


holidayList.Add(NewYearsDay(year));

holidayList.Add(MLKDay(year));

holidayList.Add(PresidentsDay(year));

holidayList.Add(MemorialDay(year));

holidayList.Add(IndependenceDay(year));

holidayList.Add(LaborDay(year));

holidayList.Add(ThanksgivingDay(year));

holidayList.Add(DayAfterThanksgivingDay(year));

holidayList.Add(ChristmasDay(year));


return holidayList;

}
 
After reading this method, there should be no doubt which holidays are accounted for. The intention of the method is explicit.

Since some of the holidays may fall on a Saturday or Sunday, they may need to be adjusted back a day (for Saturday) or forward a day (for Sunday). Hence:

private DateTime AdjustForWeekend(DateTime holiday)

{

DateTime adjustedHoliday = holiday;


switch (holiday.DayOfWeek)

{

case DayOfWeek.Saturday:

adjustedHoliday = holiday.AddDays(-1);

break;


case DayOfWeek.Sunday:

adjustedHoliday = holiday.AddDays(1);

break;


default:

break;

}


return adjustedHoliday;

}
 
We are explicitly implementing the “Holidays falling on Saturday will be observed on Friday and holidays falling on Sunday will be observed on Monday” rule. This allows us to calculate date-based holidays like this:

private DateTime NewYearsDay(int year)

{

var januaryFirst = new DateTime(year, 1, 1);

return AdjustForWeekend(januaryFirst);

}
 
New Year’s Day is January 1st, adjusted for weekends.

Next we have to deal with positional holidays, like the Labor Day (first Monday in September). I kept a couple of the helper methods that the original code had, only slightly altered:

private DateTime GetFirstDay(DateTime date, DayOfWeek dayOfWeek)

{

var dateToCheck = new DateTime(date.Year, date.Month, 1);

while (dateToCheck.DayOfWeek != dayOfWeek)

{

dateToCheck = dateToCheck.AddDays(1);

}

return dateToCheck;

}


private DateTime GetLastDay(DateTime date, DayOfWeek dayOfWeek)

{

var followingMonth = date.AddMonths(1);

var dateToCheck = new DateTime(followingMonth.Year, followingMonth.Month, 1).AddDays(-1);


while (dateToCheck.DayOfWeek != dayOfWeek)

{

dateToCheck = dateToCheck.AddDays(-1);

}

return dateToCheck;

}
 
Now that we can get the first or last DayOfWeek of any month, we can calculate all of the other holidays. Here’s Labor Day:

private DateTime LaborDay(int year)

{

var firstMondayInSeptember = GetFirstDay(new DateTime(year, 9, 1), DayOfWeek.Monday);

return firstMondayInSeptember;

}
 
In this case, I used a descriptive variable (firstMondayInSeptember) to add expressiveness, even though it isn’t necessary. It’s usefulness is more obvious when calculating Thanksgiving:

private DateTime ThanksgivingDay(int year)

{

var firstThursdayInNovember = GetFirstDay(new DateTime(year, 11, 1), DayOfWeek.Thursday);

var fourthThursdayInNovember = firstThursdayInNovember.AddDays(21);

return fourthThursdayInNovember;

}
 
Now that we have a list of holidays, we can check against that list to figure out if a given date is a holiday:

public bool IsHoliday(DateTime date)

{

var dateToCheckFor = new DateTime(date.Year, date.Month, date.Day);

return HolidaysForYear(date.Year).Contains(dateToCheckFor);

}
 
I kept much of the rest of the code the same, and I’ll leave it up to you to find other refactorings. But the end result, I hope, is Intention Revealing code. It not only meets the requirements, but does so in a way that explicitly reveals the requirements it was intended for. Incidentally, the final version has about 22% fewer lines of code (although reducing lines of code was not the goal).

Here is the final version after refactoring:

   1: namespace Your.Namespace.Here

   2: {

   3:     public class  DateService : IDateService

   4:     {

   5:         public DateProviderService()

   6:         {

   7:         }

   8:  

   9:         public bool IsBusinessDate(DateTime date)

  10:         {

  11:             return !IsWeekend(date) && !IsHoliday(date);

  12:         }

  13:  

  14:         public bool IsWeekend(DateTime date)

  15:         {

  16:             var dayOfWeek = date.DayOfWeek;

  17:             return dayOfWeek == DayOfWeek.Saturday || dayOfWeek == DayOfWeek.Sunday;

  18:         }

  19:  

  20:         public bool IsHoliday(DateTime date)

  21:         {

  22:             var dateToCheckFor = new DateTime(date.Year, date.Month, date.Day);

  23:             return HolidaysForYear(date.Year).Contains(dateToCheckFor);

  24:         }

  25:  

  26:         public DateTime CalculatePriorBusinessDate(DateTime fromDate, int numberOfBusinessDays)

  27:         {

  28:             if (numberOfBusinessDays < 0)

  29:             {

  30:                 string error = "Prior Business Days must be a positive number";

  31:                 throw new Exception(string.Format("reason : {0}", error));

  32:             }

  33:             return CalculateBusinessDate(fromDate, numberOfBusinessDays * -1);

  34:         }

  35:  

  36:         public DateTime CalculateSubsequentBusinessDate(DateTime fromDate, int numberOfBusinessDays)

  37:         {

  38:             if (numberOfBusinessDays < 0)

  39:             {

  40:                 string error = "Subsequent Business Days must be a positive number";

  41:                 throw new Exception(string.Format("reason : {0}", error));

  42:             }

  43:             return CalculateBusinessDate(fromDate, numberOfBusinessDays);

  44:         }

  45:  

  46:         public IList<DateTime> HolidaysForYear(int year)

  47:         {

  48:             var holidayList = new List<DateTime>();

  49:  

  50:             holidayList.Add(NewYearsDay(year));

  51:             holidayList.Add(MLKDay(year));

  52:             holidayList.Add(PresidentsDay(year));

  53:             holidayList.Add(MemorialDay(year));

  54:             holidayList.Add(IndependenceDay(year));

  55:             holidayList.Add(LaborDay(year));

  56:             holidayList.Add(ThanksgivingDay(year));

  57:             holidayList.Add(DayAfterThanksgivingDay(year));

  58:             holidayList.Add(ChristmasDay(year));

  59:  

  60:             return holidayList;

  61:         }

  62:  

  63:         private DateTime CalculateBusinessDate(DateTime fromDate, int numberOfDays)

  64:         {

  65:             int businessDayCount = 0;

  66:             int incrementValue = numberOfDays < 0 ? -1 : 1;

  67:             DateTime finalDate = fromDate;

  68:  

  69:             while (businessDayCount < Math.Abs(numberOfDays))

  70:             {

  71:                 finalDate = finalDate.AddDays(incrementValue);

  72:                 if (IsBusinessDate(finalDate))

  73:                 {

  74:                     businessDayCount++;

  75:                 }

  76:             }

  77:             return finalDate;

  78:         }

  79:  

  80:         private DateTime NewYearsDay(int year)

  81:         {

  82:             var januaryFirst = new DateTime(year, 1, 1);

  83:             return AdjustForWeekend(januaryFirst);

  84:         }

  85:  

  86:         private DateTime MLKDay(int year)

  87:         {

  88:             var firstMondayInJanuary = GetFirstDay(new DateTime(year, 1, 1), DayOfWeek.Monday);

  89:             var thirdMondayInJanuary = firstMondayInJanuary.AddDays(14);

  90:             return thirdMondayInJanuary;

  91:         }

  92:  

  93:         private DateTime PresidentsDay(int year)

  94:         {

  95:             var firstMondayInFebruary = GetFirstDay(new DateTime(year, 2, 1), DayOfWeek.Monday);

  96:             var thirdMondayInFebruary = firstMondayInFebruary.AddDays(14);

  97:             return thirdMondayInFebruary;

  98:         }

  99:  

 100:         private DateTime MemorialDay(int year)

 101:         {

 102:             var lastMondayInMay = GetLastDay(new DateTime(year, 5, 1), DayOfWeek.Monday);

 103:             return lastMondayInMay;

 104:         }

 105:  

 106:         private DateTime IndependenceDay(int year)

 107:         {

 108:             var julyFourth = new DateTime(year, 7, 4);

 109:             return AdjustForWeekend(julyFourth);

 110:         }

 111:  

 112:         private DateTime LaborDay(int year)

 113:         {

 114:             var firstMondayInSeptember = GetFirstDay(new DateTime(year, 9, 1), DayOfWeek.Monday);

 115:             return firstMondayInSeptember;

 116:         }

 117:  

 118:         private DateTime ThanksgivingDay(int year)

 119:         {

 120:             var firstThursdayInNovember = GetFirstDay(new DateTime(year, 11, 1), DayOfWeek.Thursday);

 121:             var fourthThursdayInNovember = firstThursdayInNovember.AddDays(21);

 122:             return fourthThursdayInNovember;

 123:         }

 124:  

 125:         private DateTime DayAfterThanksgivingDay(int year)

 126:         {

 127:             return ThanksgivingDay(year).AddDays(1);

 128:         }

 129:  

 130:         private DateTime ChristmasDay(int year)

 131:         {

 132:             var decemberTwentyFifth = new DateTime(year, 12, 25);

 133:             return AdjustForWeekend(decemberTwentyFifth);

 134:         }

 135:  

 136:         private DateTime AdjustForWeekend(DateTime holiday)

 137:         {

 138:             DateTime adjustedHoliday = holiday;

 139:  

 140:             switch (holiday.DayOfWeek)

 141:             {

 142:                 case DayOfWeek.Saturday:

 143:                     adjustedHoliday = holiday.AddDays(-1);

 144:                     break;

 145:  

 146:                 case DayOfWeek.Sunday:

 147:                     adjustedHoliday = holiday.AddDays(1);

 148:                     break;

 149:  

 150:                 default:

 151:                     break;

 152:             }

 153:  

 154:             return adjustedHoliday;

 155:         }

 156:  

 157:         private DateTime GetFirstDay(DateTime date, DayOfWeek dayOfWeek)

 158:         {

 159:             var dateToCheck = new DateTime(date.Year, date.Month, 1);

 160:             while (dateToCheck.DayOfWeek != dayOfWeek)

 161:             {

 162:                 dateToCheck = dateToCheck.AddDays(1);

 163:             }

 164:             return dateToCheck;

 165:         }

 166:  

 167:         private DateTime GetLastDay(DateTime date, DayOfWeek dayOfWeek)

 168:         {

 169:             var followingMonth = date.AddMonths(1);

 170:             var dateToCheck = new DateTime(followingMonth.Year, followingMonth.Month, 1).AddDays(-1);

 171:  

 172:             while (dateToCheck.DayOfWeek != dayOfWeek)

 173:             {

 174:                 dateToCheck = dateToCheck.AddDays(-1);

 175:             }

 176:             return dateToCheck;

 177:         }

 178:     }

 179: }