Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chriss Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Handling Holidays

Status
Not open for further replies.

DreXor

Programmer
Jun 17, 2003
2,224
US
I remember somewhere, someone had posted a question on handling holidays. i cant seem to find the thread, but this might be of assistance to others in need of finding whether or not a given date is a holiday :

args are a given date value i.e. 07/04/04
returns holiday name or true/false based on internal variable (see below)

Code:
Function IsHoliday(datevalue)
   returnholidayname=False '[green] false returns true/false value
                           ' True returns holiday name[/green]
    If not IsDate(datevalue) then 
      IsHoliday = -1
      exit function
    Else
      Datevalue = cdate(datevalue)
    End If
    YearVal = year(datevalue)
    holidays = Array("01/01/" & YearVal, "New Years", FindDate(1, "1/14/" & YearVal, False), "Martin Luther King Day", FindDate(1, "6/1/" & YearVal, True), "Labor Day", "07/04/" & YearVal, "Independance Day", FindDate(1, "9/7/" & YearVal, True), "Memorial Day", FindDate(4, "11/30/" & YearVal, True), "Thanksgiving", "12/25" & YearVal, "Christmas", "01/01/" & YearVal+1, "New Years")

'[green] the year + 1 is only for looking for possibilities of next years date, just incase the script is run right at the break of midnight, the new years for the current year of search is handled at the beginning of the array[/green]

    If returnholidayname Then
      IsHoliday = ""
    Else
      IsHoliday = False
    End If
    For Holiday = 0 To UBound(holidays) Step 2
        holidays(Holiday) = CDate(holidays(Holiday))
        If holidays(Holiday) = datevalue Then
          If returnholidayname Then
            IsHoliday = holidays(Holiday + 1)
          Else
            IsHoliday = True
          End If
          Exit For
        End If
    Next
End Function

'[green] following function is paired off with the prior function and finds a given day of the week based off a starting point
' arguments are dayval ( int 1-7 starting with monday ending with sunday )
' startdate datevalue for which to start searching
' findbackward true/false for direction of search true to cycle backwards in time, false to progress forward[/green]

Function FindDate(DayVal,StartDate,FindBackward) 
    If Not IsDate(StartDate) Then Exit Function
    StartDate = CDate(StartDate)
    If Not IsNumeric(DayVal) Then Exit Function
    DayVal = CInt(DayVal)
    On Error Resume Next
    If FindBackward Then
        For i = 1 To 8
            If WeekDay(StartDate - i, vbMonday) = DayVal Then
                FindDate = StartDate - i
                Exit Function
            End If
        Next
    Else
        For i = 0 To 6
            If WeekDay(StartDate + i, vbMonday) = DayVal Then
                FindDate = StartDate + i
                Exit Function
            End If
        Next
    End If
    FindDate = "Error"
End Function


[thumbsup2]DreX
aKa - Robert
 
forgot to mention, in the array build.. there's 2 types of holidays : set and derived

some holidays are always on a given date, others land on the first monday of a month for example, the instances where finddate is used, is a derived date to match up to a holiday.

[thumbsup2]DreX
aKa - Robert
 
for a little more dynamics, seperated the functionality of IsHoliday() so that the name can be derived seperately with WhichHoliday()

Code:
Function IsHoliday(DateVal)
    holidays = Array("01/01", "New Years", FindDate(1, "1/14", False), "Martin Luther King Day", FindDate(1, "6/1", True), "Labor Day", "07/04", "Independance Day", FindDate(1, "9/7", True), "Memorial Day", FindDate(4, "11/30", True), "Thanksgiving", "12/25", "Christmas", "01/01/" & Year(Date) + 1, "New Years")
    For Holiday = 0 To UBound(holidays) Step 2
        holidays(Holiday) = CDate(holidays(Holiday))
        If holidays(Holiday) = DateVal Then
		IsHoliday = True
        	Exit For
        End If
    Next
End Function

Function WhichHoliday(DateVal)
    holidays = Array("01/01", "New Years", FindDate(1, "1/14", False), "Martin Luther King Day", FindDate(1, "6/1", True), "Labor Day", "07/04", "Independance Day", FindDate(1, "9/7", True), "Memorial Day", FindDate(4, "11/30", True), "Thanksgiving", "12/25", "Christmas", "01/01/" & Year(Date) + 1, "New Years")
    For Holiday = 0 To UBound(holidays) Step 2
        holidays(Holiday) = CDate(holidays(Holiday))
        If holidays(Holiday) = DateVal Then
		WhichHoliday = Holidays(Holiday+1)
        	Exit For
        End If
    Next
End Function

Function FindDate(DayVal, StartDate,FindBackward)
    StartDate = CDate(StartDate)
    If Not IsNumeric(DayVal) Then Exit Function
    DayVal = CInt(DayVal)
    On Error Resume Next
    If FindBackward Then
        For i = 1 To 8
            If WeekDay(StartDate - i, vbMonday) = DayVal Then
                FindDate = StartDate - i
                Exit Function
            End If
        Next
    Else
        For i = 0 To 6
            If WeekDay(StartDate + i, vbMonday) = DayVal Then
                FindDate = StartDate + i
                Exit Function
            End If
        Next
    End If
    FindDate = "Error"
End Function

how it's useful can be seen at : ( black boxes are holidays with alt over text ) page available from 9am to 10pm CST

[thumbsup2]DreX
aKa - Robert
 
Nicely done, I'll try to hold off on alterations for a litle while ;)

-T

01000111 01101111 01110100 00100000 01000011 01101111 01100110 01100110 01100101 01100101 00111111
The never-completed website:
 
[lol]

[thumbsup2]DreX
aKa - Robert
 
Whoops, I decided to work an alternative after your last post, noticed you made an error, Monday = 2, not 1

-T

01000111 01101111 01110100 00100000 01000011 01101111 01100110 01100110 01100101 01100101 00111111
The never-completed website:
 
Note to self, be careful using theletter i as a variable in a loop that calls a function that uses i in loops, wierd things will happen :p locked up my mahcine several times couldn't figure out why it was freaking out so bad, it was bouncing back and forth between two for loops becaue the i kept getting reset, oh well.

here is the corrected version of DreXor's function, sample code, and my own 3 line solution (not counting comments or Start/End Function lines).

DreXors Corrected Code to use VB Dating scheme (1-7) instead of the scheme every otherlanguage on the planet uses (0-6):
Code:
'--- Drex's Corrected Function to use VB Dating scheme
Function FindDate(DayVal, StartDate,FindBackward)
    StartDate = CDate(StartDate)
    If Not IsNumeric(DayVal) Then Exit Function

	Dim i
	If FindBackward Then
        For i = 1 To 8
            If WeekDay(StartDate - i) = DayVal Then
                FindDate = StartDate - i
                Exit Function
            End If
        Next
    Else
        For i = 0 To 6
            If WeekDay(StartDate + i) = DayVal Then
                FindDate = StartDate + i
                Exit Function
            End If
        Next
    End If
    FindDate = "Error"
End Function

Here is my 3 line (not counting declarations and comments) version:
Code:
'Tarwn's incredibly short function with error checking :)
Function FindDate2(DayVal, StartDate,FindBackward)
	'-- Error Checks
	If Not isDate(StartDate) Then FindDate2 = "Error: Date Value not a Date" : Exit Function
    If Not IsNumeric(DayVal) Then FindDate2 = "Error: Day Value is Non-Numeric" : Exit Function

	'-- Calculation
	FindDate2 = DateAdd("d",_
			 (cInt(Not FindBackward) * -1 * (DayVal + (-7 * cInt(WeekDay(StartDate) > DayVal)) - WeekDay(StartDate)) + _
			cInt(FindBackward) * (WeekDay(StartDate) - DayVal + (cInt(WeekDay(StartDate) > DayVal) * 7 + 7))) * _
			(cInt(WeekDay(StartDate) = DayVal) + 1) _
			,StartDate)
End Function

And some sample cide, just paste thefunctions in and run it:
Code:
<%
Option Explicit

'-- Sample Output
Dim dates, dayVals, backwards, drexDayVals
dates = Array("7/1/2004","7/31/2004","7/7/2004","7/24/2004","7/1/2004","7/31/2004","7/1/2004")
dayVals = Array(2,2,2,2,6,6,7)
backwards = Array(false,true,true,false,false,true,false)

Dim j
Response.Write "new one"
Response.Write "<table border=1><tr><th>Searching For</th><th>DreX</th><Th>Tar</th></tr>"
Response.Flush

For j = 0 To Ubound(dates)
	If backwards(j) Then
		Response.Write "<tr><td>Last " & WeekDayName(dayVals(j))
	Else
		Response.Write "<tr><td>First " & WeekDayName(dayVals(j))
	End If
	Response.Write  " in " & MonthName(Month(dates(j))) & "</td>"
	Response.Write "<td>" & FindDate(dayVals(j),dates(j),backwards(j)) & "</td>"
	Response.Write "<td>" & FindDate2(dayVals(j),dates(j),backwards(j)) & "</td></tr>"
Next
Response.Write "</table>"

'-- add functions here
%>

His is probably more efficient, I didn't bother testing was just trying to see how incredibly short I could get it. I could shrink it to one line without the error chcking but I decided to leave it in :)

-T

01000111 01101111 01110100 00100000 01000011 01101111 01100110 01100110 01100101 01100101 00111111
The never-completed website:
 
tarwn.. you're a goofy fellow, with an odd fascination with shortness [lol]

thanks for the additions :)

[thumbsup2]DreX
aKa - Robert
 
i re-read through this, the finddate function was set up to find a week day the reason for the 1-8 and 0-6 is because i'm doing addition/subtraction to the actual datevalue the match on each equates out to 1-7 on the outcome date

alot of negative math in yours, you're an inverse optomist :) the glass isn't half full, it's (-.5) * (full(glass)-empty(glass))
[lol]

[thumbsup2]DreX
aKa - Robert
 
oops cant even think jokes completely through, that should be (-.5)*(empty(glass)-full(glass))

[bugeyed][lightsaber]

[thumbsup2]DreX
aKa - Robert
 
This is what I wrote and use in VB.Net. No arithmetic needed and it is static.
' M From To DOW
' 01 01 - - New Year's
' 01 02 - Monday New Year's on Sunday
' 01 15 21 Monday MLK - 3rd Monday
' 02 15 21 Monday Presidents - 3rd Monday
' 05 25 31 Monday Memorial Day - Last Monday
' 07 04 - - Independence Day
' 07 05 - Monday Independence Day on Sunday
' 09 01 07 Monday Labor Day - 1st Monday
' 10 08 14 Monday Columbus Day - 2nd Monday
' 11 11 - - Veteran's Day
' 11 12 - Monday Veteran's Day on Sunday
' 11 22 28 Thursday Thanksgiving Day - 4th Thursday
' 12 25 - - Christmas
' 12 26 - Monday Christmas Day on Sunday
Public Shared Function IsWeekdayHoliday( _
ByVal TestDate As Date) _
As Boolean
' This function returns FALSE if date is a holiday
' date BUT the day of the week is Saturday or Sunday.
' The Sat/Sun test is at the end.
Dim nDay, nMonth As Integer
Dim bIsHoliday As Boolean

nMonth = TestDate.Month
nDay = TestDate.Day

Select Case nMonth
Case 1
' January
' New Year's Day
' MLK 3rd Monday
bIsHoliday = nDay = 1 OrElse _
(nDay = 2 AndAlso _
TestDate.DayOfWeek = DayOfWeek.Monday) OrElse _
(nDay >= 15 AndAlso nDay <= 21 AndAlso _
TestDate.DayOfWeek = DayOfWeek.Monday)

Case 2
' February
' President's Day 3rd Monday
bIsHoliday = (nDay >= 15 AndAlso nDay <= 21 AndAlso _
TestDate.DayOfWeek = DayOfWeek.Monday)

Case 5
' May
'' Memorial Day Last Monday
bIsHoliday = (nDay >= 25 AndAlso _
TestDate.DayOfWeek = DayOfWeek.Monday)

Case 7
' July
' Independence Day
bIsHoliday = nDay = 4 OrElse _
(nDay = 5 AndAlso TestDate.DayOfWeek = DayOfWeek.Monday)
Case 9
' September
' Labor Day 1st Monday
bIsHoliday = (nDay <= 7 AndAlso _
TestDate.DayOfWeek = DayOfWeek.Monday)
Case 10
' October
' Columbus Day 2nd Monday
bIsHoliday = (nDay >= 8 AndAlso nDay <= 14 AndAlso _
TestDate.DayOfWeek = DayOfWeek.Monday)
Case 11
' November
' Veteran's Day Nov 11
' Thanksgiving Day 4th Thursday
bIsHoliday = nDay = 11 OrElse _
(nDay = 12 AndAlso TestDate.DayOfWeek = DayOfWeek.Monday) OrElse _
(nDay >= 22 AndAlso nDay <= 28 AndAlso _
TestDate.DayOfWeek = DayOfWeek.Thursday)

Case 12
' December
' Christmas Day
bIsHoliday = nDay = 25 OrElse _
(nDay = 26 AndAlso TestDate.DayOfWeek = DayOfWeek.Monday)

End Select

' If Saturday or Sunday then never a weekday holiday.
' Tested here to avoid DayOfWeek call unless it could be a Holiday.

If bIsHoliday Then
Select Case TestDate.DayOfWeek()
Case DayOfWeek.Saturday, DayOfWeek.Sunday
Return False
Case Else
Return True
End Select
End If
End Function



Forms/Controls Resizing/Tabbing
Compare Code
Generate Sort Class in VB
Check To MS)
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top