Calculate US Bank Holidays

Moderator: Rathinagiri

Post Reply
User avatar
RussBaker
Posts: 45
Joined: Wed Jul 22, 2015 9:44 am

Calculate US Bank Holidays

Post by RussBaker » Mon Aug 10, 2015 10:13 pm

I need to calculate US bank holidays to validate a deposit date in a form.
Before I re-invent the wheel or convert the following code to HMG, anyone have something like this already?

fill the list with holidays
' New Year's Day Jan 1
' Martin Luther King, Jr. third Mon in Jan
' Washington's Birthday third Mon in Feb
' Memorial Day last Mon in May
' Independence Day July 4
' Labor Day first Mon in Sept
' Columbus Day second Mon in Oct
' Veterans Day Nov 11
' Thanksgiving Day fourth Thur in Nov
' Christmas Day Dec 25

Below is some C Code I could borrow for the job.

Code: Select all

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))

    ' 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

User avatar
esgici
Posts: 4363
Joined: Wed Jul 30, 2008 9:17 pm
DBs Used: DBF
Location: iskenderun / Turkiye
Has thanked: 250 times
Been thanked: 91 times
Contact:

Post by esgici » Tue Aug 11, 2015 10:42 am

RussBaker wrote:I need to calculate US bank holidays to validate a deposit date in a form.
Before I re-invent the wheel or convert the following code to HMG, anyone have something like this already?
Hi Russ

We have a built-in function FT_EASTER; but only for Easter day, no other holidays; still may be useful to you.

In comp.lang.clipper forum there is a pretty old (2004) topic US holidays including a pseudo function and some discussion on the topic.

I hope you would write such function and all we are will be utilized :arrow:

Happy HMG'ing :D
Viva INTERNATIONAL HMG :D

User avatar
dhaine_adp
Posts: 457
Joined: Wed Aug 06, 2008 12:22 pm
Location: Manila, Philippines
Been thanked: 1 time

Post by dhaine_adp » Tue Aug 11, 2015 6:27 pm

Hi,

Here's a brute force HB implementation of the VB code you have mentioned on your post.

Syntax in calling getHolidays()

Code: Select all

aHolidays_ := getHolidays( 2015, .t. )    // 2nd parameter add asterisk to those holiday(s) that has been moved.
aHolidays_ := getHolidays( 2017 )          // no asterisk added
aHolidays_ := getHolidays()                   // Use current system date

Code: Select all

************************************
function getHolidays( zYear, lMark )

   LOCAL aDates_ := ARRAY( 10 )
   LOCAL aElem_  := { 1, 5, 8, 10 }    // array offset (dates) that possibly needs to be moved, others not required
   LOCAL ii
   LOCAL lAsterisk := .f.

   IF PCOUNT() = 1 .AND. VALTYPE( zYear ) == "N"
      zYear := ALLTRIM( HB_NTOS( zYear ) )
   ELSE
      zYear := ALLTRIM( HB_NTOS( YEAR( DATE() ) ) )
   ENDIF
   IF VALTYPE( lMark ) == "U"; lMark := .f.; ENDIF

   aDates_[  1 ] := CTOD( "01/01/" + zYear )          // New Year's Day Jan 1
   aDates_[  2 ] := getDate( 1, zYear,  3, "MON" )    // Martin Luther King, Jr. third Mon in Jan
   aDates_[  3 ] := getDate( 2, zYear,  3, "MON" )    // Washington's Birthday third Mon in Feb
   aDates_[  4 ] := getDate( 5, zYear,  4, "MON" )    // Memorial Day last Mon in May
   aDates_[  5 ] := CTOD( "07/04/" + zYear )          // Independence Day July 4
   aDates_[  6 ] := getDate( 9, zYear,  1, "MON" )    // Labor Day first Mon in Sept
   aDates_[  7 ] := getDate( 10, zYear,  2, "MON" )   // Columbus Day second Mon in Oct
   aDates_[  8 ] := CTOD( "11/11/" + zYear )          // Veterans Day Nov 11
   aDates_[  9 ] := getDate( 11, zYear,  4, "THU" )   // Thanksgiving Day fourth Thur in Nov
   aDates_[ 10 ] := CTOD( "12/25/" + zYear )          // Christmas Day Dec 25

   // Move holidays that falls on saturday to Fri; Sun to Mon
   FOR ii := 1 TO LEN( aElem_ )
      IF DOW( aDates_[ aElem_[ ii ] ] ) == 7  // Saturday
         aDates_[ aElem_[ ii ] ] -= 1
         IF lMark; lAsterisk := .t.; ENDIF

         ELSEIF DOW( aDates_[ aElem_[ ii ] ] ) == 1  // Sunday
            aDates_[ aElem_[ ii ] ] += 1
            IF lMark; lAsterisk := .t.; ENDIF
      ELSE
         /* Skip, do nothing. */
      ENDIF
      **--> mark with asterisk those holidays that have been moved.
      **    Its value will become a character string.
      ******************************************************************
      IF lAsterisk
         aDates_[ aElem_[ ii ] ] := "*" + DTOC( aDates_[ aElem_[ ii ] ] )
         lAsterisk := .f.
      ENDIF
   NEXT
   RETURN aDates_



*****************************************************
static function getDate( nMonth, cYear, nWkNo, cDOW )

   LOCAL dRetVal
   LOCAL dTarget
   LOCAL nWkCtr := 1
   
   dTarget := CTOD( ALLTRIM( HB_NTOS( nMonth ) ) + "/01/" + cYear )
   WHILE nWkCtr <= nWkNo
      IF LEFT( UPPER( CDOW( dTarget ) ), 3 ) == cDOW
         nWkCtr++
      ENDIF
      dTarget++
   END
   dTarget--   // when the loop terminates, the date falls on the the following day so it has to be adjusted backward
   RETURN dTarget
Regards,

Danny
Manila, Philippines

User avatar
bpd2000
Posts: 964
Joined: Sat Sep 10, 2011 4:07 am
Location: India
Has thanked: 137 times
Been thanked: 43 times

Post by bpd2000 » Tue Aug 11, 2015 6:32 pm

Nice coding, Thank you Mr. Danny
Holidays list can be maintained in like .ini file? and universally function can be used?
BPD
Convert Dream into Reality through HMG

User avatar
dhaine_adp
Posts: 457
Joined: Wed Aug 06, 2008 12:22 pm
Location: Manila, Philippines
Been thanked: 1 time

Post by dhaine_adp » Tue Aug 11, 2015 7:38 pm

Holidays list can be maintained in like .ini file? and universally function can be used?
Hi BPD2000,

I took the question marks (usage) as a question. My answer is yes and no. Yes it can be put on .ini and no because different countries have their own unique set of holidays. However personally I don't put holidays on .ini file. I put them in a table and use mm/dd as a code. Sometimes holiday is mandated by president/gov't official as a Special Non-Working Holiday. In this regard users are able to add holiday or exclude/include in the calculation for a given fiscal year, bank transactions, check clearing, Time calculation, OT, night differential (shift workers), etc.
Regards,

Danny
Manila, Philippines

User avatar
esgici
Posts: 4363
Joined: Wed Jul 30, 2008 9:17 pm
DBs Used: DBF
Location: iskenderun / Turkiye
Has thanked: 250 times
Been thanked: 91 times
Contact:

Post by esgici » Tue Aug 11, 2015 11:40 pm

bpd2000 wrote:Nice coding, Thank you Mr. Danny...
+1

Regards
Viva INTERNATIONAL HMG :D

User avatar
bpd2000
Posts: 964
Joined: Sat Sep 10, 2011 4:07 am
Location: India
Has thanked: 137 times
Been thanked: 43 times

Post by bpd2000 » Wed Aug 12, 2015 4:50 am

Thank you Danny for explanation
In India there is variable holidays declared every year and my idea was that any user can add / delete holidays date w/o
our intervention
BPD
Convert Dream into Reality through HMG

Post Reply