Don't like ads? PRO users don't see any ads ;-)
Guest

Untitled

By: a guest on Jul 6th, 2012  |  syntax: None  |  size: 14.46 KB  |  hits: 10  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. Using SQL to calculate a date within a certain date range
  2. Option Compare Database
  3. Option Explicit
  4.  
  5. ' ********* Code Start **************
  6. '
  7. ' Modified from code in
  8. ' "Visual Basic Language Developer's Handbook"
  9. ' by Ken Getz and Mike Gilbert
  10. ' Copyright 2000; Sybex, Inc. All rights reserved.
  11. '
  12.  
  13. Public Function dhAddWorkDaysA(lngDays As Long, Optional dtmDate As Date = 0)
  14. 'Optional adtmDates As Variant) As Date
  15.     ' Add the specified number of work days to the
  16.     ' specified date.
  17.  
  18.     ' Modified from code in
  19.     ' "Visual Basic Language Developer's Handbook"
  20.     ' by Ken Getz and Mike Gilbert
  21.     ' Copyright 2000; Sybex, Inc. All rights reserved.
  22.  
  23.     ' In:
  24.     '   lngDays:
  25.     '       Number of work days to add to the start date.
  26.     '   dtmDate:
  27.     '       date on which to start looking.
  28.     '       Use the current date, if none was specified.
  29.     '   adtmDates (Optional):
  30.     '       Array containing holiday dates. Can also be a single
  31.     '       date value, if that's what you want.
  32.     ' Out:
  33.     '   Return Value:
  34.     '       The date of the working day lngDays from the start, taking
  35.     '       into account weekends and holidays.
  36.     ' Example:
  37.     '   dhAddWorkDaysA(10, #2/9/2000#, Array(#2/16/2000#, #2/17/2000#))
  38.     '   returns #2/25/2000#, which is the date 10 work days
  39.     '   after 2/9/2000, if you treat 2/16 and 2/17 as holidays
  40.     '   (just made-up holidays, for example purposes only).
  41.  
  42.     ' Did the caller pass in a date? If not, use
  43.     ' the current date.
  44.     Dim lngCount As Long
  45.     Dim dtmTemp As Date
  46.     Dim adtmDates() As Variant
  47.  
  48.     'loadup the adtmDates with all the records from the table tblNon_working_days
  49.  
  50.     Dim rst As DAO.Recordset
  51.     Dim i As Long
  52.  
  53.     Set rst = DBEngine(0)(0).OpenRecordset("SELECT Date FROM tblNon_working_days", dbOpenForwardOnly)
  54.     With rst
  55.         If .RecordCount > 0 Then
  56.             i = 1
  57.             Do Until .EOF
  58.                 ReDim Preserve adtmDates(i)
  59.                 adtmDates(i) = !Date
  60.                 .MoveNext
  61.                i = i + 1
  62.             Loop
  63.         End If
  64.     End With
  65.  
  66.     rst.Close
  67.  
  68.     Set rst = Nothing
  69.  
  70.     If dtmDate = 0 Then
  71.         dtmDate = Date
  72.     End If
  73.  
  74.     dtmTemp = dtmDate
  75.     For lngCount = 1 To lngDays
  76.         dtmTemp = dhNextWorkdayA(dtmTemp, adtmDates)
  77.     Next lngCount
  78.     dhAddWorkDaysA = dtmTemp
  79. End Function
  80.  
  81. Public Function dhNextWorkdayA( _
  82. Optional dtmDate As Date = 0, _
  83. Optional adtmDates As Variant = Empty) As Date
  84.  
  85.     ' Return the next working day after the specified date.
  86.  
  87.     ' Modified from code in
  88.     ' "Visual Basic Language Developer's Handbook"
  89.     ' by Ken Getz and Mike Gilbert
  90.     ' Copyright 2000; Sybex, Inc. All rights reserved.
  91.  
  92.     ' Requires:
  93.     '   SkipHolidays
  94.     '   IsWeekend
  95.  
  96.     ' In:
  97.     '   dtmDate:
  98.     '       date on which to start looking.
  99.     '       Use the current date, if none was specified.
  100.     '   adtmDates (Optional):
  101.     '       Array containing holiday dates. Can also be a single
  102.     '       date value.
  103.     ' Out:
  104.     '   Return Value:
  105.     '       The date of the next working day, taking
  106.     '       into account weekends and holidays.
  107.     ' Example:
  108.     '   ' Find the next working date after 5/30/97
  109.     '   dtmDate = dhNextWorkdayA(#5/23/1997#, #5/26/97#)
  110.     '   ' dtmDate should be 5/27/97, because 5/26/97 is Memorial day.
  111.  
  112.     ' Did the caller pass in a date? If not, use
  113.     ' the current date.
  114.     If dtmDate = 0 Then
  115.         dtmDate = Date
  116.     End If
  117.  
  118.     dhNextWorkdayA = SkipHolidaysA(adtmDates, dtmDate + 1, 1)
  119. End Function
  120.  
  121. Public Function dhPreviousWorkdayA( _
  122. Optional dtmDate As Date = 0, _
  123. Optional adtmDates As Variant = Empty) As Date
  124.  
  125.     ' Return the previous working day before the specified date.
  126.  
  127.     ' Modified from code in
  128.     ' "Visual Basic Language Developer's Handbook"
  129.     ' by Ken Getz and Mike Gilbert
  130.     ' Copyright 2000; Sybex, Inc. All rights reserved.
  131.  
  132.     ' Requires:
  133.     '   SkipHolidays
  134.     '   IsWeekend
  135.  
  136.     ' In:
  137.     '   dtmDate:
  138.     '       date on which to start looking.
  139.     '       Use the current date, if none was specified.
  140.     '   adtmDates (Optional):
  141.     '       Array containing holiday dates. Can also be a single
  142.     '       date value.
  143.     ' Out:
  144.     '   Return Value:
  145.     '       The date of the previous working day, taking
  146.     '       into account weekends and holidays.
  147.     ' Example:
  148.     '   ' Find the next working date before 1/1/2000
  149.  
  150.     '   dtmDate = dhPreviousWorkdayA(#1/1/2000#, Array(#12/31/1999#, #1/1/2000#))
  151.     '   ' dtmDate should be 12/30/1999, because of the New Year's holidays.
  152.  
  153.     ' Did the caller pass in a date? If not, use
  154.     ' the current date.
  155.     If dtmDate = 0 Then
  156.         dtmDate = Date
  157.     End If
  158.  
  159.     dhPreviousWorkdayA = SkipHolidaysA(adtmDates, dtmDate - 1, -1)
  160. End Function
  161.  
  162. Public Function dhFirstWorkdayInMonthA( _
  163. Optional dtmDate As Date = 0, _
  164. Optional adtmDates As Variant = Empty) As Date
  165.  
  166.     ' Return the first working day in the month specified.
  167.  
  168.     ' Modified from code in
  169.     ' "Visual Basic Language Developer's Handbook"
  170.     ' by Ken Getz and Mike Gilbert
  171.     ' Copyright 2000; Sybex, Inc. All rights reserved.
  172.  
  173.     ' Requires:
  174.     '   SkipHolidays
  175.     '   IsWeekend
  176.  
  177.     ' In:
  178.     '   dtmDate:
  179.     '       date within the month of interest.
  180.     '       Use the current date, if none was specified.
  181.     '   adtmDates (Optional):
  182.     '       Array containing holiday dates. Can also be a single
  183.     '       date value.
  184.     ' Out:
  185.     '   Return Value:
  186.     '       The date of the first working day in the month, taking
  187.     '       into account weekends and holidays.
  188.     ' Example:
  189.     '   ' Find the first working day in 1999
  190.     '   dtmDate = dhFirstWorkdayInMonthA(#1/1/1999#, #1/1/1999#)
  191.  
  192.     Dim dtmTemp As Date
  193.  
  194.     ' Did the caller pass in a date? If not, use
  195.     ' the current date.
  196.     If dtmDate = 0 Then
  197.         dtmDate = Date
  198.     End If
  199.  
  200.     dtmTemp = DateSerial(Year(dtmDate), Month(dtmDate), 1)
  201.     dhFirstWorkdayInMonthA = SkipHolidaysA(adtmDates, dtmTemp, 1)
  202. End Function
  203.  
  204. Public Function dhLastWorkdayInMonthA( _
  205. Optional dtmDate As Date = 0, _
  206. Optional adtmDates As Variant = Empty) As Date
  207.  
  208.     ' Return the last working day in the month specified.
  209.  
  210.     ' Modified from code in
  211.     ' "Visual Basic Language Developer's Handbook"
  212.     ' by Ken Getz and Mike Gilbert
  213.     ' Copyright 2000; Sybex, Inc. All rights reserved.
  214.  
  215.     ' Requires:
  216.     '   SkipHolidays
  217.     '   IsWeekend
  218.  
  219.     ' In:
  220.     '   dtmDate:
  221.     '       date within the month of interest.
  222.     '       Use the current date, if none was specified.
  223.     '   adtmDates (Optional):
  224.     '       Array containing holiday dates. Can also be a single
  225.     '       date value.
  226.     ' Out:
  227.     '   Return Value:
  228.     '       The date of the last working day in the month, taking
  229.     '       into account weekends and holidays.
  230.     ' Example:
  231.     '   ' Find the last working day in 1999
  232.     '   dtmDate = dhLastWorkdayInMonthA(#12/1/1999#, #12/31/1999#)
  233.  
  234.     Dim dtmTemp As Date
  235.  
  236.     ' Did the caller pass in a date? If not, use
  237.     ' the current date.
  238.     If dtmDate = 0 Then
  239.         dtmDate = Date
  240.     End If
  241.  
  242.     dtmTemp = DateSerial(Year(dtmDate), Month(dtmDate) + 1, 0)
  243.     dhLastWorkdayInMonthA = SkipHolidaysA(adtmDates, dtmTemp, -1)
  244. End Function
  245.  
  246. Public Function dhCountWorkdaysA(ByVal dtmStart As Date, ByVal dtmEnd As Date, _
  247.  Optional adtmDates As Variant = Empty) _
  248.  As Integer
  249.  
  250.     ' Count the business days (not counting weekends/holidays) in
  251.     ' a given date range.
  252.  
  253.     ' Modified from code in
  254.     ' "Visual Basic Language Developer's Handbook"
  255.     ' by Ken Getz and Mike Gilbert
  256.     ' Copyright 2000; Sybex, Inc. All rights reserved.
  257.  
  258.     ' Requires:
  259.     '   SkipHolidays
  260.     '   CountHolidays
  261.     '   IsWeekend
  262.  
  263.     ' In:
  264.     '   dtmStart:
  265.     '       Date specifying the start of the range (inclusive)
  266.     '   dtmEnd:
  267.     '       Date specifying the end of the range (inclusive)
  268.     '       (dates will be swapped if out of order)
  269.     '   adtmDates (Optional):
  270.     '       Array containing holiday dates. Can also be a single
  271.     '       date value.
  272.     ' Out:
  273.     '   Return Value:
  274.     '       Number of working days (not counting weekends and optionally, holidays)
  275.     '       in the specified range.
  276.     ' Example:
  277.     '   Debug.Print dhCountWorkdaysA(#7/2/2000#, #7/5/2000#, _
  278.     '    Array(#1/1/2000#, #7/4/2000#))
  279.     '
  280.     '   returns 2, because 7/2/2000 is Sunday, 7/4/2000 is a holiday,
  281.     '   leaving 7/3 and 7/5 as workdays.
  282.  
  283.     Dim intDays As Integer
  284.     Dim dtmTemp As Date
  285.     Dim intSubtract As Integer
  286.  
  287.     ' Swap the dates if necessary.>
  288.     If dtmEnd < dtmStart Then
  289.         dtmTemp = dtmStart
  290.         dtmStart = dtmEnd
  291.         dtmEnd = dtmTemp
  292.     End If
  293.  
  294.     ' Get the start and end dates to be weekdays.
  295.     dtmStart = SkipHolidaysA(adtmDates, dtmStart, 1)
  296.     dtmEnd = SkipHolidaysA(adtmDates, dtmEnd, -1)
  297.     If dtmStart > dtmEnd Then
  298.         ' Sorry, no Workdays to be had. Just return 0.
  299.         dhCountWorkdaysA = 0
  300.     Else
  301.         intDays = dtmEnd - dtmStart + 1
  302.  
  303.         ' Subtract off weekend days.  Do this by figuring out how
  304.         ' many calendar weeks there are between the dates, and
  305.         ' multiplying the difference by two (because there are two
  306.         ' weekend days for each week). That is, if the difference
  307.         ' is 0, the two days are in the same week. If the
  308.         ' difference is 1, then we have two weekend days.
  309.         intSubtract = (DateDiff("ww", dtmStart, dtmEnd) * 2)
  310.  
  311.         ' The answer to our quest is all the weekdays, minus any
  312.         ' holidays found in the table.
  313.         intSubtract = intSubtract + _
  314.          CountHolidaysA(adtmDates, dtmStart, dtmEnd)
  315.  
  316.         dhCountWorkdaysA = intDays - intSubtract
  317.     End If
  318. End Function
  319.  
  320. Private Function CountHolidaysA( _
  321. adtmDates As Variant, _
  322. dtmStart As Date, dtmEnd As Date) As Long
  323.  
  324.     ' Count holidays between two end dates.
  325.     '
  326.     ' Modified from code in
  327.     ' "Visual Basic Language Developer's Handbook"
  328.     ' by Ken Getz and Mike Gilbert
  329.     ' Copyright 2000; Sybex, Inc. All rights reserved.
  330.  
  331.     ' Required by:
  332.     '   dhCountWorkdays
  333.  
  334.     ' Requires:
  335.     '   IsWeekend
  336.  
  337.  
  338.     Dim lngItem As Long
  339.     Dim lngCount As Long
  340.     Dim blnFound As Long
  341.     Dim dtmTemp As Date
  342.  
  343.     On Error GoTo HandleErr
  344.     lngCount = 0
  345.     Select Case VarType(adtmDates)
  346.         Case vbArray + vbDate, vbArray + vbVariant
  347.             ' You got an array of variants, or of dates.
  348.             ' Loop through, looking for non-weekend values
  349.             ' between the two endpoints.
  350.             For lngItem = LBound(adtmDates) To UBound(adtmDates)
  351.                 dtmTemp = adtmDates(lngItem)
  352.                 If dtmTemp >= dtmStart And dtmTemp <= dtmEnd Then
  353.                     If Not IsWeekend(dtmTemp) Then
  354.                         lngCount = lngCount + 1
  355.                     End If
  356.                 End If
  357.             Next lngItem
  358.         Case vbDate
  359.             ' You got one date. So see if it's a non-weekend
  360.             ' date between the two endpoints.
  361.             If adtmDates >= dtmStart And adtmDates <= dtmEnd Then
  362.                 If Not IsWeekend(adtmDates) Then
  363.                     lngCount = 1
  364.                 End If
  365.             End If
  366.     End Select
  367.  
  368. ExitHere:
  369.     CountHolidaysA = lngCount
  370.     Exit Function
  371.  
  372. HandleErr:
  373.     ' No matter what the error, just
  374.     ' return without complaining.
  375.     ' The worst that could happen is that the code
  376.     ' include a holiday as a real day, even if
  377.     ' it's in the table.
  378.     Resume ExitHere
  379. End Function
  380.  
  381. Private Function FindItemInArray(varItemToFind As Variant, _
  382. avarItemsToSearch As Variant) As Boolean
  383.     Dim lngItem As Long
  384.  
  385.     On Error GoTo HandleErrors
  386.  
  387.     For lngItem = LBound(avarItemsToSearch) To UBound(avarItemsToSearch)
  388.         If avarItemsToSearch(lngItem) = varItemToFind Then
  389.             FindItemInArray = True
  390.             GoTo ExitHere
  391.         End If
  392.     Next lngItem
  393.  
  394. ExitHere:
  395.     Exit Function
  396.  
  397. HandleErrors:
  398.     ' Do nothing at all.
  399.     ' Return False.
  400.     Resume ExitHere
  401. End Function
  402.  
  403. Private Function IsWeekend(dtmTemp As Variant) As Boolean
  404.     ' If your weekends aren't Saturday (day 7) and Sunday (day 1),
  405.     ' change this routine to return True for whatever days
  406.     ' you DO treat as weekend days.
  407.  
  408.     ' Modified from code in "Visual Basic Language Developer's Handbook"
  409.     ' by Ken Getz and Mike Gilbert
  410.     ' Copyright 2000; Sybex, Inc. All rights reserved.
  411.  
  412.     ' Required by:
  413.     '   SkipHolidays
  414.     '   dhFirstWorkdayInMonth
  415.     '   dbLastWorkdayInMonth
  416.     '   dhNextWorkday
  417.     '   dhPreviousWorkday
  418.     '   dhCountWorkdays
  419.  
  420.     If VarType(dtmTemp) = vbDate Then
  421.         Select Case WeekDay(dtmTemp)
  422.             Case vbSaturday, vbSunday
  423.                 IsWeekend = True
  424.             Case Else
  425.                 IsWeekend = False
  426.         End Select
  427.     End If
  428. End Function
  429.  
  430. Private Function SkipHolidaysA( _
  431. adtmDates As Variant, _
  432. dtmTemp As Date, intIncrement As Integer) As Date
  433.     ' Skip weekend days, and holidays in the array referred to by adtmDates.
  434.     ' Return dtmTemp + as many days as it takes to get to a day that's not
  435.     ' a holiday or weekend.
  436.  
  437.     ' Modified from code in
  438.     ' "Visual Basic Language Developer's Handbook"
  439.     ' by Ken Getz and Mike Gilbert
  440.     ' Copyright 2000; Sybex, Inc. All rights reserved.
  441.  
  442.     ' Required by:
  443.     '   dhFirstWorkdayInMonthA
  444.     '   dbLastWorkdayInMonthA
  445.     '   dhNextWorkdayA
  446.     '   dhPreviousWorkdayA
  447.     '   dhCountWorkdaysA
  448.  
  449.     ' Requires:
  450.     '   IsWeekend
  451.  
  452.     Dim strCriteria As String
  453.     Dim strFieldName As String
  454.     Dim lngItem As Long
  455.     Dim blnFound As Boolean
  456.  
  457.     On Error GoTo HandleErrors
  458.  
  459.     ' Move up to the first Monday/last Friday, if the first/last
  460.     ' of the month was a weekend date. Then skip holidays.
  461.     ' Repeat this entire process until you get to a weekday.
  462.     ' Unless adtmDates an item for every day in the year (!)
  463.     ' this should finally converge on a weekday.
  464.  
  465.     Do
  466.         Do While IsWeekend(dtmTemp)
  467.             dtmTemp = dtmTemp + intIncrement
  468.         Loop
  469.         Select Case VarType(adtmDates)
  470.             Case vbArray + vbDate, vbArray + vbVariant
  471.                 Do
  472.                     blnFound = FindItemInArray(dtmTemp, adtmDates)
  473.                     If blnFound Then
  474.                         dtmTemp = dtmTemp + intIncrement
  475.                     End If
  476.                 Loop Until Not blnFound
  477.             Case vbDate
  478.                 If dtmTemp = adtmDates Then
  479.                     dtmTemp = dtmTemp + intIncrement
  480.                 End If
  481.         End Select
  482.     Loop Until Not IsWeekend(dtmTemp)
  483.  
  484. ExitHere:
  485.     SkipHolidaysA = dtmTemp
  486.     Exit Function
  487.  
  488. HandleErrors:
  489.     ' No matter what the error, just
  490.     ' return without complaining.
  491.     ' The worst that could happen is that we
  492.     ' include a holiday as a real day, even if
  493.     ' it's in the array.
  494.     Resume ExitHere
  495.  
  496. End Function