How to calculate holidays for the USA
Converted to C# as a console program... I needed the dates in a text file quickly:
class Program
{
public class Holiday
{
public string HolidayName { get; set; }
public DateTime Date { get; set; }
public Holiday(string holidayName, DateTime date)
{
HolidayName = holidayName;
Date = date;
}
}
public static List<Holiday> getHolidayList(int vYear)
{
int FirstWeek = 1;
int SecondWeek = 2;
int ThirdWeek = 3;
int FourthWeek = 4;
int LastWeek = 5;
List<Holiday> HolidayList = new List<Holiday>();
// http://www.usa.gov/citizens/holidays.shtml
// http://archive.opm.gov/operating_status_schedules/fedhol/2013.asp
// New Year's Day Jan 1
HolidayList.Add(new Holiday("NewYears", new DateTime(vYear, 1, 1)));
// Martin Luther King, Jr. third Mon in Jan
HolidayList.Add(new Holiday("MLK", GetNthDayOfNthWeek(new DateTime(vYear, 1, 1), DayOfWeek.Monday, ThirdWeek)));
// Washington's Birthday third Mon in Feb
HolidayList.Add(new Holiday("WashingtonsBDay", GetNthDayOfNthWeek(new DateTime(vYear, 2, 1), DayOfWeek.Monday, ThirdWeek)));
// Memorial Day last Mon in May
HolidayList.Add(new Holiday("MemorialDay", GetNthDayOfNthWeek(new DateTime(vYear, 5, 1), DayOfWeek.Monday, LastWeek)));
// Independence Day July 4
HolidayList.Add(new Holiday("IndependenceDay", new DateTime(vYear, 7, 4)));
// Labor Day first Mon in Sept
HolidayList.Add(new Holiday("LaborDay", GetNthDayOfNthWeek(new DateTime(vYear, 9, 1), DayOfWeek.Monday, FirstWeek)));
// Columbus Day second Mon in Oct
HolidayList.Add(new Holiday("Columbus", GetNthDayOfNthWeek(new DateTime(vYear, 10, 1), DayOfWeek.Monday, SecondWeek)));
// Veterans Day Nov 11
HolidayList.Add(new Holiday("Veterans", new DateTime(vYear, 11, 11)));
// Thanksgiving Day fourth Thur in Nov
HolidayList.Add(new Holiday("Thanksgiving", GetNthDayOfNthWeek(new DateTime(vYear, 11, 1), DayOfWeek.Thursday, FourthWeek)));
// Christmas Day Dec 25
HolidayList.Add(new Holiday("Christmas", new DateTime(vYear, 12, 25)));
//saturday holidays are moved to Fri; Sun to Mon
foreach (var holiday in HolidayList)
{
if (holiday.Date.DayOfWeek == DayOfWeek.Saturday)
{
holiday.Date = holiday.Date.AddDays(-1);
}
if (holiday.Date.DayOfWeek == DayOfWeek.Sunday)
{
holiday.Date = holiday.Date.AddDays(1);
}
}
//return
return HolidayList;
}
private static System.DateTime GetNthDayOfNthWeek(DateTime dt, DayOfWeek dayofWeek, int WhichWeek)
{
//specify which day of which week of a month and this function will get the date
//this function uses the month and year of the date provided
//get first day of the given date
System.DateTime dtFirst = new DateTime(dt.Year, dt.Month, 1);
//get first DayOfWeek of the month
System.DateTime dtRet = dtFirst.AddDays(6 - (int)dtFirst.AddDays(-1 * ((int)dayofWeek + 1)).DayOfWeek);
//get which week
dtRet = dtRet.AddDays((WhichWeek - 1) * 7);
//if day is past end of month then adjust backwards a week
if (dtRet >= dtFirst.AddMonths(1))
{
dtRet = dtRet.AddDays(-7);
}
//return
return dtRet;
}
static void Main(string[] args)
{
for(int ii = 2013; ii < 2100; ii++)
{
var holidays = getHolidayList(ii);
foreach (var holiday in holidays)
{
Console.WriteLine(holiday.HolidayName + ": " + holiday.Date.ToShortDateString());
}
}
}
}
Jay Muntz on CodeProject has an excellent implementation of holidays using an XML file to store the rules. That code doesn't adjust for weekends though.
Also his version of tax day (April 15) doesn't correct for Emancipation Day in Washington DC although that may be irrelevant for this question.
Dynamic Holiday Date Calculator By Jay Muntz, 5 Jan 2006
This is one way to do it. A weakness of this method is that since the rules are hard coded I would need to change the code in the rare event that congress changed the rules. For my in-house software that is not a problem but it might be for others.
Also I don't calculate Easter since that is not a US federal holiday. See Nature (1876) Algorithm for Calculating the Date of Easter
Public Function getHolidayList(ByVal vYear As Integer) As List(Of Date)
Dim FirstWeek As Integer = 1
Dim SecondWeek As Integer = 2
Dim ThirdWeek As Integer = 3
Dim FourthWeek As Integer = 4
Dim LastWeek As Integer = 5
Dim HolidayList As New List(Of Date)
' http://www.usa.gov/citizens/holidays.shtml
' http://archive.opm.gov/operating_status_schedules/fedhol/2013.asp
' New Year's Day Jan 1
HolidayList.Add(DateSerial(vYear, 1, 1))
' Martin Luther King, Jr. third Mon in Jan
HolidayList.Add(GetNthDayOfNthWeek(DateSerial(vYear, 1, 1), DayOfWeek.Monday, ThirdWeek))
' Washington's Birthday third Mon in Feb
HolidayList.Add(GetNthDayOfNthWeek(DateSerial(vYear, 2, 1), DayOfWeek.Monday, ThirdWeek))
' Memorial Day last Mon in May
HolidayList.Add(GetNthDayOfNthWeek(DateSerial(vYear, 5, 1), DayOfWeek.Monday, LastWeek))
' Juneteenth National Independence Day, June 19
HolidayList.Add(DateSerial(vYear, 6, 19))
' Independence Day July 4
HolidayList.Add(DateSerial(vYear, 7, 4))
' Labor Day first Mon in Sept
HolidayList.Add(GetNthDayOfNthWeek(DateSerial(vYear, 9, 1), DayOfWeek.Monday, FirstWeek))
' Columbus Day second Mon in Oct
HolidayList.Add(GetNthDayOfNthWeek(DateSerial(vYear, 10, 1), DayOfWeek.Monday, SecondWeek))
' Veterans Day Nov 11
HolidayList.Add(DateSerial(vYear, 11, 11))
' Thanksgiving Day fourth Thur in Nov
HolidayList.Add(GetNthDayOfNthWeek(DateSerial(vYear, 11, 1), DayOfWeek.Thursday, FourthWeek))
' Christmas Day Dec 25
HolidayList.Add(DateSerial(vYear, 12, 25))
'saturday holidays are moved to Fri; Sun to Mon
For i As Integer = 0 To HolidayList.Count - 1
Dim dt As Date = HolidayList(i)
If dt.DayOfWeek = DayOfWeek.Saturday Then
HolidayList(i) = dt.AddDays(-1)
End If
If dt.DayOfWeek = DayOfWeek.Sunday Then
HolidayList(i) = dt.AddDays(1)
End If
Next
'return
Return HolidayList
End Function
Private Function GetNthDayOfNthWeek(ByVal dt As Date, ByVal DayofWeek As Integer, ByVal WhichWeek As Integer) As Date
'specify which day of which week of a month and this function will get the date
'this function uses the month and year of the date provided
'get first day of the given date
Dim dtFirst As Date = DateSerial(dt.Year, dt.Month, 1)
'get first DayOfWeek of the month
Dim dtRet As Date = dtFirst.AddDays(6 - dtFirst.AddDays(-(DayofWeek + 1)).DayOfWeek)
'get which week
dtRet = dtRet.AddDays((WhichWeek - 1) * 7)
'if day is past end of month then adjust backwards a week
If dtRet >= dtFirst.AddMonths(1) Then
dtRet = dtRet.AddDays(-7)
End If
'return
Return dtRet
End Function
For reference, the list of Federal Holidays is defined in 5 U.S. Code § 6103. Holidays:
- New Year’s Day, January 1.
- Birthday of Martin Luther King, Jr., the third Monday in January.
- Washington’s Birthday, the third Monday in February.
- Memorial Day, the last Monday in May.
- Juneteenth National Independence Day, June 19. (Newly added as of 2021)
- Independence Day, July 4.
- Labor Day, the first Monday in September.
- Columbus Day, the second Monday in October.
- Veterans Day, November 11.
- Thanksgiving Day, the fourth Thursday in November.
- Christmas Day, December 25.
For regular Monday through Friday workers, holidays that land on a Saturday will be observed on the Friday before. I've read in other places that holidays landing on a Sunday will be observed the following Monday.