Introduction
While doing the code for the tip here - US Federal Holidays (C#) - I
also created a couple of static methods that would allow me to determine the date of a specific Holiday in a given year.
The SQL version of this tip is here.
Background
The code
The following methods and enumerators should be placed exist in a public static class. Since I'm creating extension methods for the .Net DateTime struct, I call my class ExtendDateTime. The name of the class is unimportant, so you can call yours FruitRollup if you'd like to.
We start off by defining an enumerator that identifies the holidays in which we are interested.
public enum Holiday { NewYears, MLKDay, PresidentsDay, MemorialDay, IndependenceDay, LaborDay, ColumbusDay, VeteransDay, Thanksgiving, Christmas };
Next, we implement some helper methods. The comments tell the story, so it would be pointless to describe the method in narrative form. Suffice it to say that this is where the magic
happens.
public static DateTime HolidayOnWeekend(this DateTime date)
{
DateTime newDate = date;
if (date.DayOfWeek == DayOfWeek.Saturday)
{
newDate = newDate.AddDays(-1);
}
else if (date.DayOfWeek == DayOfWeek.Sunday)
{
newDate = newDate.AddDays(1);
}
return newDate;
}
public static bool GetDateByOrdinalDay(int year,
int month,
DayOfWeek dayOfWeek,
int ordinal,
out DateTime ordinalDate)
{
bool result = false;
ordinalDate = new DateTime(0);
if (ordinal >= 1 && ordinal <= 5 &&
month >= 1 && month <= 12 &&
year >= 0 && year <= 9999)
{
month = Math.Min(Math.Max(month, 1), 12);
DateTime workingDate = new DateTime(year, month, 1);
workingDate = (int)workingDate.DayOfWeek > (int)dayOfWeek
? workingDate.AddDays(7 - (int)workingDate.DayOfWeek + (int)dayOfWeek)
: workingDate.AddDays((int)dayOfWeek - (int)workingDate.DayOfWeek);
workingDate = workingDate.AddDays((ordinal - 1) * 7);
if (workingDate.Month == month)
{
ordinalDate = workingDate;
result = true;
}
}
return result;
}
Finally, we have the reason we're all attending this party. This is the method you call to actually find a specific holiday. The only thing this method does is calls one of the two helper methods shown above.
public static DateTime FindFederalHoliday(int year, Holiday holiday)
{
DateTime result = new DateTime(0);
switch (holiday)
{
case Holiday.Christmas : result = HolidayOnWeekend(new DateTime(year, 12, 25)); break;
case Holiday.IndependenceDay : result = HolidayOnWeekend(new DateTime(year, 7, 4)); break;
case Holiday.NewYears : result = HolidayOnWeekend(new DateTime(year, 1, 1)); break;
case Holiday.VeteransDay : result = HolidayOnWeekend(new DateTime(year, 11, 11)); break;
case Holiday.MemorialDay :
if (GetDateByOrdinalDay(year, 6, DayOfWeek.Monday, 1, out result))
{
result = result.AddDays(-7);
}
break;
case Holiday.Thanksgiving : GetDateByOrdinalDay(year, 11, DayOfWeek.Thursday, 4, out result); break;
case Holiday.ColumbusDay : GetDateByOrdinalDay(year, 10, DayOfWeek.Monday, 2, out result); break;
case Holiday.LaborDay : GetDateByOrdinalDay(year, 9, DayOfWeek.Monday, 1, out result); break;
case Holiday.MLKDay : GetDateByOrdinalDay(year, 1, DayOfWeek.Monday, 3, out result); break;
case Holiday.PresidentsDay : GetDateByOrdinalDay(year, 2, DayOfWeek.Monday, 3, out result); break;
}
return result;
}
Usage
To find the date for Thanksgiving 2017, for example, all you have to do is:
DateTime thanksgiving = ExtendDateTime.FindHoliday(2017, ExtendDateTime.Holiday.Thanksgiving);
If you have a holiday you want to find the date of that isn't covered in the list of US federal holidays, you can call the appropriate helper method directly. For instance, if you want to find the date on which Mother's Day (2nd Sunday in May) occurs in 2017, you would do this:
DateTime mothersDay = ExtendDateTime.GetDateByOrdinalDay(2017, 5, DayOfWeek.Sunday, 2);
FYI, Easter is not not determined using either of the helper methods described in this tip. If you want to determine the date of Easter Sunday, refer to this tip: When is Easter?
Points of Interest
Chuck Norris ignores The Periodic Table Of Elements, because all he recognizes is the element of Surprise.
History
02 Feb 2017 - Original submission.