You've got a holiday and the basic information about it.
What types of holidays do we have? There are the fixed holidays, the moving holidays and the "I'm not even going to bother calculating" holidays (Easter, I'm looking at you).
For this, you would have subtables.
There are the fixed, repeating holidays. Things like Christmas and the Forth of July. These are holidays that fall on the same day of the month each year.
Then you've also got the movable ones. Labor day (first Monday in September), Memorial day (last Monday in May), Thanksgiving (forth Thursday in November).
The easiest way to approach this is to give a day range for the day.
If your database supports a range type you may wish to use that. Not all do, and thus the two date approach.
Why two days? Lets look at Labor day. The earliest it can be is September 1st - if Monday falls on the first. The latest that the first Monday can fall is September 6th. Monday on September 7th would mean that September 1st was a Monday and that was Labor Day.
For Memorial day, the last Monday in May (which has 31 days), the range for valid dates is the 25th through the 31st.
Some example rows:
MoveableHoliday | Labor | Memorial | Thanksgiving
MonthOfYear | Sep | May | Nov
DayOfWeek | Mon | Mon | Thurs
EarliestDay | 1 | 25 | 22
LatestDay | 6 | 31 | 28
This brings us to the "I'm not even going to calculate that" approach - it's the first Sunday after the first full moon that occurs on or after the 21st of March... and yea. If you really dug into it, you might write a stored procedure that has the calculation in it for full moon (or have that in another table - again, needing to populate that table), or you can just say "there aren't enough of these to really make a difference" and just populate it.
This is very much like the fixed holiday, except that its for one year only.
At this point, you just populate the table however you want for however far you want.
Now, you could put the SpecificDayHoliday and the FixedHoldiay tables together, and make Year optional. However, I feel that this makes it an easier to work with each table - they each have a single type of value that goes into them. In particular, SpecificDayHoliday allows for multiple HolidayId values to be the same in the table. FixedHoliday and MoveableHoliday should have a constraint on the table that makes HolidayId unique within the table.