65.9K
CodeProject 正在变化。 阅读更多。
Home

处理业务日期(节假日/周末等)

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.06/5 (17投票s)

2003年12月10日

5分钟阅读

viewsIcon

123308

downloadIcon

876

本项目旨在简化计算有效业务日的难题。它包含我创建的几个函数,用于确定日期是否为节假日或周末,以及获取下一个或上一个业务日。

引言

本项目旨在简化计算有效业务日的难题。它包含我创建的几个函数,用于确定日期是否为节假日或周末,以及获取下一个或上一个业务日。还有一个函数用于查找给定月份的最后一天。我包含了伪代码,可以帮助您将这些函数翻译成其他语言。

背景

在工作中,您经常会遇到一些意想不到的场景。根据我的经验,业务日期给我带来了最大的麻烦,而且问题层出不穷。当您认为代码已经完美时,一个恰好落在周末的节假日,而那一年碰巧还是闰年,并且太阳恰好移动到火星左侧,我的代码就会崩溃,1200 笔银行交易会认为已完成,但银行却不知道我们在说什么,因为他们关门了,真是傻。:)

因此,我们的目标是编写一套完美的例程来处理日历可能出现的潜在问题。由于我们美丽的星球在自转,我们必须考虑许多有趣的问题,例如闰年以及每个月的天数没有固定规律。幸运的是,除了二月之外,每年都一样,否则我们真的会陷入困境。所以,话不多说,这是我尝试创建的完美业务日期例程,以处理我遇到的大部分问题。

在处理任何业务日期函数时,重要的是要注意,有两种主要类型的日期会影响我们处理数据的方式。

浮动节假日(圣诞节、新年、退伍军人节等)

浮动节假日是指日期固定不变,但星期几总是不固定的节假日。例如,圣诞节总是 12 月 25 日,但可能落在任何一个星期。因此,它是一个浮动节假日。

固定节假日(阵亡将士纪念日、劳动节、感恩节等)

固定节假日是指每年日期不同,但星期几总是固定的节假日。例如,马丁·路德·金纪念日总是 1 月的第三个星期一。

注意 - 请注意,这些函数并非旨在解决您所有的问题。它们需要您根据您所在地的节假日和标准进行一些调整。例如,我们公司处理交易有两天延迟,所以我们会将所有业务日期增加 2 天,因此重要的是要注意您的标准。

根据您公司的运作方式,您使用的节假日可能与其他人不同。例如,有些银行的节假日可能不是所有州都承认,而有些州可能有银行不承认的节假日。在我的例子中,我们将假设世界在我们所在的地区(华盛顿州)根据州和银行的节假日关闭。您需要相应地进行调整。

Using the Code

LastDayOfMonth:传入您需要获取该月最后一天的月份和年份。我们将它拆分成两个参数,以帮助解决我们在使用定期付款时遇到的一些其他问题,稍后我将解释。

Function LastDayOfMonth(sMonth, sYear)
'Returns the last day of the month/year passed in "mm/dd/yyyy" format
dim tmpMonth, tmpYear
tmpMonth = sMonth
tmpYear = sYear

LastDayOfMonth = dateadd("d", -1, Dateadd("m", 1, tmpMonth & "/1/" & tmpYear))
End Function

IsHoliday:传入您要验证的日期。如果日期是节假日,则返回 1,如果不是,则返回 0。然后您可以使用 DateAdd 并将返回的值添加到当前日期(您传入的日期)。至于此函数中的节假日,请确保如果您的节假日是浮动节假日,您需要包含前一天和后一天,以防主要节假日落在周末。请参见 12/24、25、26 作为示例。

Function IsHoliday(sDate)
'Checks to see if passed date is a holiday
Dim iDay, iTmpDay, i

IsHoliday = 0
iDay = Day(sDate)

'Check if valid date first
If IsDate(sDate) Then
    Select Case Month(sDate)

        Case 1  'Jan
            If iDay = 1 Then  'New Years
                IsHoliday = 1
            Else
         If iDay = 2 Then  'Make sure new years doesn't fall on sunday. 
                           'If so, today is a holiday.
                        if Weekday(DateAdd("d", -1, sDate)) = 1 then
                IsHoliday = 1
            end if
             Else
            For i = 0 To 30     'Martin Luther King B-Day
                If Weekday(DateAdd("d", i, CDate("1/1/" & Year(sDate)))) _
                              = 2 Then
                    If CDate(sDate) = CDate(DateAdd("d", i + 14, _
                          CDate("1/1/" & Year(sDate)))) Then
                        IsHoliday = 1
                    End If
                    Exit For  'PG 1/28
                End If
            Next 
        End If
            End If

        Case 2  'Feb
        For i = 0 To 27     'President's Day
           If Weekday(DateAdd("d", i, CDate("2/1/" & Year(sDate)))) = 2 _
                    Then
            If CDate(sDate) = CDate(DateAdd("d", i + 14, _
                    CDate("2/1/" & Year(sDate)))) Then
               IsHoliday = 1
            End If
            Exit For 
         End If
      Next 

        Case 3  'Mar
        Case 4  'Apr

        Case 5  'May
            For i = 1 To 7  'Memorial Day
                If Weekday(DateAdd("d", "-" & i, _
                     CDate("5/31/" & Year(sDate)))) = 2 Then
                    If CDate(sDate) = CDate(DateAdd("d", "-" & i, _
                      CDate("5/31/" & Year(sDate)))) Then
                        IsHoliday = 1
                    End If
                    Exit For
                End If
            Next 

        Case 6  'Jun

        Case 7  'Jul
    If iDay = 4 Then  'Independence Day
        IsHoliday = 1
    Else
        If iDay = 3 Then  'Make sure Independence Day doesn't 
                     'fall on saturday. If so, Friday is a holiday.
                      if Weekday(DateAdd("d", 1, sDate)) = 7 then
                IsHoliday = 1
            end if
        Else    
            If iDay = 5 Then  'Make sure Independence 
                    'Day doesn't fall on sunday. If so, Monday is a holiday.
                if Weekday(DateAdd("d", -1, sDate)) = 1 then
                    IsHoliday = 1
                end if
            End If
        End If
    End If

        Case 8 'Aug

        Case 9 'Sep
            For i = 0 To 13  'Labor Day
                If Weekday(DateAdd("d", i, CDate("9/1/" & _
                        Year(sDate)))) = 2 Then
                    If CDate(sDate) = CDate(DateAdd("d", i, _
                           CDate("9/1/" & Year(sDate)))) Then
                        IsHoliday = 1
                    End If
                    Exit For
                End If
            Next 

        Case 10 'Oct
    For i = 0 To 13  'Columbus Day
       If Weekday(DateAdd("d", i, CDate("10/1/" & _
                      Year(sDate)))) = 2 Then
          If CDate(sDate) = CDate(DateAdd("d", i + 7, CDate("10/1/" & _
                  Year(sDate)))) Then
             IsHoliday = 1
          End If
            Exit For
       End If
    Next 

        Case 11 'Nov
    If iDay = 11 Then  'Veteran's Day
       IsHoliday = 1
    Else
       If iDay = 10 Then  'Make sure Veterans Day doesn't fall 
                   'on saturday. If so, Friday is a holiday.
          if Weekday(DateAdd("d", 1, sDate)) = 7 then
             IsHoliday = 1
          end if
       Else    
          If iDay = 12 Then  'Make sure Veterans Day doesn't 
                   'fall on sunday. If so, Monday is a holiday.
             if Weekday(DateAdd("d", -1, sDate)) = 1 then
                IsHoliday = 1
             end if
          Else
             For i = 0 To 28     'Thanksgiving & the Day After
                If Weekday(DateAdd("d", i, CDate("11/1/" & _
                    Year(sDate)))) = 5 Then 'this is the first 
                               'thursday of the month
                   if datediff("d", sDate,  DateAdd("d", i + 21, _
                         CDate("11/1/" & Year(sDate)))) = 0 then 'add 3 
                             'weeks to the first to get the 4th (thanksgiving)
                      IsHoliday = 1
                      Exit For
                    End If
                End if
                If Weekday(DateAdd("d", i, CDate("11/1/" & _
                     Year(sDate)))) = 6 Then 'this is the day 
                              'after thanksgiving
                   if datediff("d", sDate,  DateAdd("d", i + 21,_
                        CDate("11/1/" & Year(sDate)))) = 0 then
                      IsHoliday = 1
                      Exit For
                   End If            
                 End if
             Next
          End If
       End If
    End If

        Case 12 'Dec
    If iDay = 25 Then  'Christmas
       IsHoliday = 1
    Else
       If iDay = 24 Then  'Make sure Christmas Day doesn't 
              'fall on saturday. If so, Friday is a holiday.
          if Weekday(DateAdd("d", 1, sDate)) = 7 then
             IsHoliday = 1
          end if
       Else    
          If iDay = 26 Then  'Make sure Christmas 
               'Day doesn't fall on sunday. If so, Monday is a holiday.
             if Weekday(DateAdd("d", -1, sDate)) = 1 then
                IsHoliday = 1
             end if
          Else
             If iDay = 31 Then  'Make sure new years 
                  'doesn't fall on saturday. If so, today is a holiday.
                if Weekday(DateAdd("d", 1, sDate)) = 7 then
                   IsHoliday = 1
                End if
             End if
          End if
       End if
    End If

        Case Else
            'Do nothing but return false

    End Select
End If

End Function

LastBusinessDay:此函数将返回基于传入日期的上一个业务日(即非节假日、非周末)。

Function LastBusinessDay(sDate)
Dim iDay, iDaysToAdd, iDate

iDaysToAdd = 0
iDate = sDate

x = 1

Do while iDaysToAdd >= 0
   If Weekday(iDate) = 1 or Weekday(iDate) = 7 or _
             isHoliday(iDate) <> 0 then
      iDay = Weekday(iDate)
      Select Case cint(iDay)
         Case 1  'Sunday
                      iDate = DateAdd("d", -1, iDate)
         Case 7  'Saturday
                      iDate = DateAdd("d", -1, iDate)
         Case else    'this is a valid day
                      if isHoliday(iDate) > 0 then
                         iDate = dateadd("d", -(isHoliday(iDate)), iDate)
                      else
                         iDaysToAdd = iDaysToAdd - 1
                      end if
         End Select
   end if
Loop

LastBusinessDay = iDate
End Function

AddBusinessDay:将传入的业务天数加到传入日期上。如果传入 0,此例程将验证传入的日期是否为业务日,如果不是,则返回下一个业务日。

Function AddBusinessDay(sDate, sAdd)
'Adds given number of business days to date.
Dim iDay, iDaysToAdd, iDate

iDaysToAdd = sAdd
iDate = sDate

x = 1
Do while iDaysToAdd >= 0
   If Weekday(iDate) = 1 or Weekday(iDate) = 7 or _
           isHoliday(iDate) <> 0 then
      iDay = Weekday(iDate)
      Select Case cint(iDay)
         Case 1  'Sunday
                      iDate = dateadd("d", 1, iDate)
         Case 7    'Saturday
                      iDate = DateAdd("d", 1, iDate)
         Case else    'this is a valid day
                      if isHoliday(iDate) > 0 then
                         iDate = dateadd("d", isHoliday(iDate), iDate)
                      else
                         iDaysToAdd = iDaysToAdd - 1
                      end if
         End Select
   else
      if iDaysToAdd > 0 then
         iDate = DateAdd("d", 1, iDate)
      end if
      iDaysToAdd = iDaysToAdd - 1
   end if

   'Error trap in case of infinite loop, good for testing, 
     'shouldn't be necessary, but nice just in case
   if x > 100 then
      response.End()
      iDaysToAdd = -1
   else
      x = x + 1
   end if
Loop

AddBusinessDay = iDate
end function

关注点

使用示例

在支付系统中,您可以使用这些函数来确定进行支付的有效日期。如果提交一次性支付于 2005 年 1 月 1 日,我们需要验证:

  1. 该日期是否是节假日或周末
  2. 该日期是否临近周末的节假日?

直到以上条件都不成立,我们才能继续。一个常见的错误是先检查周末,然后检查节假日(反之亦然),但问题在于,如果您有一个周五的节假日,在增加 1 天后,您将永远不会再次检查新日期是否为周末。这就是为什么我们将它嵌套在一个循环中,直到返回一个有效日期。

调用日期例程时,我们必须传入日期以及我们希望将交易延迟多少天。在大多数情况下,交易不是即时的,所以您必须传入交易真正发生前的天数,而这个差值必须是业务天数,这说明了为什么我们需要这些例程。如果您不想延迟,只需传入 0,它将返回下一个有效的业务日。

Pseudo Example
AddBusinessDay(“01/01/2005”, 0)
Date = “01/01/2005”, DaysToAdd = 0

Loop while DaysToAdd parameter is equal to, or greater than, 0.

First time through
    “01/01/2005” is a Weekend or Holiday then
        “01/01/2005” is Saturday
            Set Date = “01/02/2005”
Second time through
    “01/02/2005” is a weekend or Holiday then
        “01/02/2005” is Sunday
            Set Date = “01/03/2005”
Third time through
    “01/03/2005” is not a weekend or Holiday
        There are no Days to Add
        Subtract 1 from the DaysToAdd total

DateReturned = “01/03/2005”, DaysToAdd = -1
Return New Date
End AddBusinessDay Function

最后一点说明: 如果交易在您的截止时间之后发出,则在日期上额外增加 1 天。例如,如果您的交易在下午 5 点进行,那么之后提交的任何新付款都将在第二天真正发送。所以我们必须额外增加 1 天。

就是这样!

如果您发现我忘记了任何场景或遗漏了任何数据,请告诉我。正如我之前所说,日期问题可能很棘手,我希望让这些函数尽可能强大。所以如果您有任何改进它们的想法,请随时告诉我。

许可证

本文未附加明确的许可证,但可能在文章文本或下载文件本身中包含使用条款。如有疑问,请通过下面的讨论区联系作者。

作者可能使用的许可证列表可以在此处找到。

© . All rights reserved.