|
Holidays
|
Often it is useful to return the date of a holiday for a given year, perhaps for a
schedule application. Neither Excel nor VBA have any built in functions
for working with holidays -- you have to create your own. Holidays
can be thought of as being either Fixed or Floating. Fixed holidays are
those that occur on the same day each year, such as Christmas.
Floating holidays are those which occur on different days in different
years. For example, Thanksgiving (in the US) occurs on the fourth Thursday
of November. Therefore, we need a function that will calculate the fourth
Thursday. We'll generalize that function, in both VBA and worksheet
function form, to return the Nth day-of-week for any month and
year.
Other floating holidays are a bit harder to calculate. For example, in
the US, Memorial Day occurs on the last Monday of May. Depending on the
year, this may be either the 4th or 5th Monday. So we need a function to
calculate the number of Mondays in May. We'll generalize this to compute
the number of any day-of-week in any month and year.
Finally, there is Easter, whose actual date is some bizarre result of the
phases of the moon. I don't claim credit for the formulas for calculating Easter
shown below, nor do I claim to understand why the work, but they do.
Fixed Holidays
For fixed holidays, such as Christmas, this is simple since the date of the holiday
does not change from year to year. For example, use the following to return the date
of Christmas in the current year:
=DATE(YEAR(NOW()),12,25)
Floating Holidays
Other holidays, however, are not assigned to a specific date. For example,
Thanksgiving Day is defined to be the 4th Thursday of November. Therefore its exact
date will change from year to year. For Thanksgiving, we have an explicit VBA
function:
Public Function ThanksgivingDate(Yr As Integer) As Date
ThanksgivingDate = DateSerial(Yr, 11, 29 - _
WeekDay(DateSerial(Yr, 11, 1), vbFriday))
End Function
We can generalize this to holidays that are defined as the Nth Day of some month, such
as Martin Luther King's birthday, celebrated on the 3rd Monday of January. The
following function will return the Nth DayOfWeek for a given month and year:
Public Function NDow(Y As Integer, M As Integer,
_
N As Integer,
DOW As Integer) As Date
NDow = DateSerial(Y, M, (8 - WeekDay(DateSerial(Y, M, 1), _
(DOW + 1) Mod 8)) + ((N - 1) *
7))
End Function
To return the date of the 3rd Monday in January of 1998, use
=NDow (1998, 1, 3, 2)
The NDow function can also be written as a worksheet formula:
=DATE(Yr,Mon,1+((Nth-(DoW>=WEEKDAY(DATE(Yr,Mon,1))))*7)
+(DoW-WEEKDAY(DATE(Yr,Mon,1))))
Where Yr,Mon,
and DoW are cell
references or values indicating Year, Month, Nth, and Day-Of-Week.
This will work fine for most floating holidays. However, Memorial Day is celebrated
on the Last Monday of May. To compute this date, we first need a function to tell us
how many Mondays there are in the month.
Public Function DOWsInMonth(Yr As Integer, M As Integer,
_
DOW
As Integer) As Integer
On Error GoTo EndFunction
Dim I As Integer
Dim Lim As Integer
Lim = Day(DateSerial(Yr, M + 1, 0))
DOWsInMonth = 0
For I = 1 To Lim
If WeekDay(DateSerial(Yr, M, I)) = DOW Then
DOWsInMonth = DOWsInMonth + 1
End If
Next I
Exit Function
EndFunction:
DOWsInMonth = 0
End Function
Calling this function will tell us how many Mondays there are in May, 1998.
=DOWsInMonth(1998, 5, 2)
The
DOWsInMonth can
also be written as a worksheet function with the following
array formula. Note that it will not work properly unless you
press CTRL+SHIFT+ENTER instead of just ENTER when you first enter the
formula and whenever you edit it later. If you do this properly, Excel will
display the formula in the formula bar enclosed in curly braces {}. |
|
| |
=SUM((WEEKDAY(DATE(B3,C3,(ROW(INDIRECT
("1:"&DAY(DATE(B3,C3+1,0)))))))=D3)*1)
where B3 is the year,
C3 is the month, and
D3 is the day
of week (1=Sunday, 2=Monday, ..., 7=Saturday)
There are 4 Mondays in May, 1998. The we can pass this into the NDOW function, to return 25-May-1998, the date of
Memorial Day. Therefore, the formula to return the date of Memorial Day in
1999 would be
=NDow(1999,5,DowsInMonth(1999,5,2),2)
|
|
|
Easter
Finally, there is Easter, whose date is very complicated to determine from year to
year. I did not write the following formula. I don't know who did, but
it seems to work.
Public Function EasterDate(Yr As Integer) As Date
Dim d As Integer
d = (((255 - 11 * (Yr Mod 19)) - 21) Mod 30) + 21
EasterDate = DateSerial(Yr, 3, 1) + d + (d > 48) + 6 - ((Yr + Yr \ 4 + _
d + (d > 48) + 1) Mod 7)
End Function
You can also calculate the date of Easter with a worksheet
function. For USA style dates (mm/dd/yyyy), use
=FLOOR("5/"&DAY(MINUTE(B2/38)/2+56)&"/"&B2,7)-34
where B 2
contains the year for which you want to calculate Easter.
For European style dates (dd/mm/yyyy), use
=FLOOR(DAY(MINUTE(B2/38)/2+56)&"/5/"&B2,7)-34
Another formula, which does not rely on date formatting was submitted by
Joost Verbeek.
=FLOOR(DATE(B2,5,DAY(MINUTE(B2/38)/2+56)),7)-34
|
|
|