2010-04-07 20 views
1

두 날짜의 차이를 확인하는 방법을 찾고 있습니다. 정상적인 SQL DATEDIFF 문은 작업 시간과 요일 즉 주말과 16:00 - 7:00 사이의 시간을 제외해야하므로 잘라 내지 않습니다.날짜 차이, 특정 시간 및 날짜 제외

Excel의 NETWORKDAYS 기능과 비슷한 기능을 제공합니다.

저는 스프레드 시트를 코딩하고 있습니다. VBA를 사용하여 SQL 서버에 연결하여 데이터를 가져옵니다.

+0

그래서 매일의 길이는 9/24 = 0.375입니까? –

+0

나는 이것을 한 번 시도했지만 그것을 얻을 수 없었지만 기본적으로 시작 날짜부터 한 단계 씩 단계별로 코드를 작성하여 시간/날짜 변수를 전진시켜야했다. 행운을 빕니다. –

답변

3

다음은 인터넷에서 가져 와서 액세스 테이블에 저장된 날짜 테이블과 작동하도록 수정 한 코드 샘플입니다. 워크 시트 등에서 범위를 가리 키도록 다시 변경할 수 있다고 확신하지만 기본 아이디어는 대우를 작동합니다.

Option Compare Database 
Option Explicit 

Public Function dhCountWorkdaysA(ByVal dtmStart As Date, ByVal dtmEnd As Date, _ 
Optional adtmDates As Variant = Empty) _ 
As Integer 

    ' Count the business days (not counting weekends/holidays) in 
    ' a given date range. 

    ' Modified from code in 
    ' "Visual Basic Language Developer's Handbook" 
    ' by Ken Getz and Mike Gilbert 
    ' Copyright 2000; Sybex, Inc. All rights reserved. 

    ' Requires: 
    ' SkipHolidays 
    ' CountHolidays 
    ' IsWeekend 

    ' In: 
    ' dtmStart: 
    '  Date specifying the start of the range (inclusive) 
    ' dtmEnd: 
    '  Date specifying the end of the range (inclusive) 
    '  (dates will be swapped if out of order) 
    ' adtmDates (Optional): 
    '  Array containing holiday dates. Can also be a single 
    '  date value. 
    ' Out: 
    ' Return Value: 
    '  Number of working days (not counting weekends and optionally, holidays) 
    '  in the specified range. 
    ' Example: 
    ' Debug.Print dhCountWorkdaysA(#7/2/2000#, #7/5/2000#, _ 
    ' Array(#1/1/2000#, #7/4/2000#)) 
    ' 
    ' returns 2, because 7/2/2000 is Sunday, 7/4/2000 is a holiday, 
    ' leaving 7/3 and 7/5 as workdays. 

    Dim intDays As Integer 
    Dim dtmTemp As Date 
    Dim intSubtract As Integer 

    ' Swap the dates if necessary.> 
    If dtmEnd < dtmStart Then 
     dtmTemp = dtmStart 
     dtmStart = dtmEnd 
     dtmEnd = dtmTemp 
    End If 

    ' Get the start and end dates to be weekdays. 
    dtmStart = SkipHolidaysA(adtmDates, dtmStart, 1) 
    dtmEnd = SkipHolidaysA(adtmDates, dtmEnd, -1) 
    If dtmStart > dtmEnd Then 
     ' Sorry, no Workdays to be had. Just return 0. 
     dhCountWorkdaysA = 0 
    Else 
     intDays = dtmEnd - dtmStart + 1 

     ' Subtract off weekend days. Do this by figuring out how 
     ' many calendar weeks there are between the dates, and 
     ' multiplying the difference by two (because there are two 
     ' weekend days for each week). That is, if the difference 
     ' is 0, the two days are in the same week. If the 
     ' difference is 1, then we have two weekend days. 
     intSubtract = (DateDiff("ww", dtmStart, dtmEnd) * 2) 

     ' The answer to our quest is all the weekdays, minus any 
     ' holidays found in the table. 
     intSubtract = intSubtract + _ 
     CountHolidaysA(adtmDates, dtmStart, dtmEnd) 

     dhCountWorkdaysA = intDays - intSubtract 
    End If 
End Function 
Private Function CountHolidaysA(_ 
adtmDates As Variant, _ 
dtmStart As Date, dtmEnd As Date) As Long 

    ' Count holidays between two end dates. 
    ' 
    ' Modified from code in 
    ' "Visual Basic Language Developer's Handbook" 
    ' by Ken Getz and Mike Gilbert 
    ' Copyright 2000; Sybex, Inc. All rights reserved. 

    ' Required by: 
    ' dhCountWorkdays 

    ' Requires: 
    ' IsWeekend 


    Dim lngItem As Long 
    Dim lngCount As Long 
    Dim blnFound As Long 
    Dim dtmTemp As Date 

    On Error GoTo HandleErr 
    lngCount = 0 
    Select Case VarType(adtmDates) 
     Case vbArray + vbDate, vbArray + vbVariant 
      ' You got an array of variants, or of dates. 
      ' Loop through, looking for non-weekend values 
      ' between the two endpoints. 
      For lngItem = LBound(adtmDates) To UBound(adtmDates) 
       dtmTemp = adtmDates(lngItem) 
       If dtmTemp >= dtmStart And dtmTemp <= dtmEnd Then 
        If Not IsWeekend(dtmTemp) Then 
         lngCount = lngCount + 1 
        End If 
       End If 
      Next lngItem 
     Case vbDate 
      ' You got one date. So see if it's a non-weekend 
      ' date between the two endpoints. 
      If adtmDates >= dtmStart And adtmDates <= dtmEnd Then 
       If Not IsWeekend(adtmDates) Then 
        lngCount = 1 
       End If 
      End If 
    End Select 

ExitHere: 
    CountHolidaysA = lngCount 
    Exit Function 

HandleErr: 
    ' No matter what the error, just 
    ' return without complaining. 
    ' The worst that could happen is that the code 
    ' include a holiday as a real day, even if 
    ' it's in the table. 
    Resume ExitHere 
End Function 


Public Function dhAddWorkDaysA(lngDays As Long, Optional dtmDate As Date = 0) 
'Optional adtmDates As Variant) As Date 
    ' Add the specified number of work days to the 
    ' specified date. 

    ' Modified from code in 
    ' "Visual Basic Language Developer's Handbook" 
    ' by Ken Getz and Mike Gilbert 
    ' Copyright 2000; Sybex, Inc. All rights reserved. 

    ' In: 
    ' lngDays: 
    '  Number of work days to add to the start date. 
    ' dtmDate: 
    '  date on which to start looking. 
    '  Use the current date, if none was specified. 
    ' adtmDates (Optional): 
    '  Array containing holiday dates. Can also be a single 
    '  date value, if that's what you want. 
    ' Out: 
    ' Return Value: 
    '  The date of the working day lngDays from the start, taking 
    '  into account weekends and holidays. 
    ' Example: 
    ' dhAddWorkDaysA(10, #2/9/2000#, Array(#2/16/2000#, #2/17/2000#)) 
    ' returns #2/25/2000#, which is the date 10 work days 
    ' after 2/9/2000, if you treat 2/16 and 2/17 as holidays 
    ' (just made-up holidays, for example purposes only). 

    ' Did the caller pass in a date? If not, use 
    ' the current date. 
    Dim lngCount As Long 
    Dim dtmTemp As Date 
    Dim adtmDates() As Variant 

    'loadup the adtmDates with all the records from the table tblNon_working_days 
    Dim db As DAO.Database 
    Dim rst As DAO.Recordset 
    Dim i As Long 


    Set rst = DBEngine(0)(0).OpenRecordset("tblNon_working_days", dbOpenSnapshot) 
    With rst 
     If .RecordCount > 0 Then 
      i = 1 
      .MoveFirst 
      Do Until .EOF 
       ReDim Preserve adtmDates(i) 
       adtmDates(i) = !Date 
       .MoveNext 
       i = i + 1 
      Loop 
     End If 
    End With 

    rst.Close 
    db.Close 
    Set rst = Nothing 
    Set db = Nothing 

    If dtmDate = 0 Then 
     dtmDate = Date 
    End If 

    dtmTemp = dtmDate 
    For lngCount = 1 To lngDays 
     dtmTemp = dhNextWorkdayA(dtmTemp, adtmDates) 
    Next lngCount 
    dhAddWorkDaysA = dtmTemp 
End Function 
Public Function dhNextWorkdayA(_ 
Optional dtmDate As Date = 0, _ 
Optional adtmDates As Variant = Empty) As Date 

    ' Return the next working day after the specified date. 

    ' Modified from code in 
    ' "Visual Basic Language Developer's Handbook" 
    ' by Ken Getz and Mike Gilbert 
    ' Copyright 2000; Sybex, Inc. All rights reserved. 

    ' Requires: 
    ' SkipHolidays 
    ' IsWeekend 

    ' In: 
    ' dtmDate: 
    '  date on which to start looking. 
    '  Use the current date, if none was specified. 
    ' adtmDates (Optional): 
    '  Array containing holiday dates. Can also be a single 
    '  date value. 
    ' Out: 
    ' Return Value: 
    '  The date of the next working day, taking 
    '  into account weekends and holidays. 
    ' Example: 
    ' ' Find the next working date after 5/30/97 
    ' dtmDate = dhNextWorkdayA(#5/23/1997#, #5/26/97#) 
    ' ' dtmDate should be 5/27/97, because 5/26/97 is Memorial day. 

    ' Did the caller pass in a date? If not, use 
    ' the current date. 
    If dtmDate = 0 Then 
     dtmDate = Date 
    End If 

    dhNextWorkdayA = SkipHolidaysA(adtmDates, dtmDate + 1, 1) 
End Function 
Private Function SkipHolidaysA(_ 
adtmDates As Variant, _ 
dtmTemp As Date, intIncrement As Integer) As Date 
    ' Skip weekend days, and holidays in the array referred to by adtmDates. 
    ' Return dtmTemp + as many days as it takes to get to a day that's not 
    ' a holiday or weekend. 

    ' Modified from code in 
    ' "Visual Basic Language Developer's Handbook" 
    ' by Ken Getz and Mike Gilbert 
    ' Copyright 2000; Sybex, Inc. All rights reserved. 

    ' Required by: 
    ' dhFirstWorkdayInMonthA 
    ' dbLastWorkdayInMonthA 
    ' dhNextWorkdayA 
    ' dhPreviousWorkdayA 
    ' dhCountWorkdaysA 

    ' Requires: 
    ' IsWeekend 

    Dim strCriteria As String 
    Dim strFieldName As String 
    Dim lngItem As Long 
    Dim blnFound As Boolean 

    On Error GoTo HandleErrors 

    ' Move up to the first Monday/last Friday, if the first/last 
    ' of the month was a weekend date. Then skip holidays. 
    ' Repeat this entire process until you get to a weekday. 
    ' Unless adtmDates an item for every day in the year (!) 
    ' this should finally converge on a weekday. 

    Do 
     Do While IsWeekend(dtmTemp) 
      dtmTemp = dtmTemp + intIncrement 
     Loop 
     Select Case VarType(adtmDates) 
      Case vbArray + vbDate, vbArray + vbVariant 
       Do 
        blnFound = FindItemInArray(dtmTemp, adtmDates) 
        If blnFound Then 
         dtmTemp = dtmTemp + intIncrement 
        End If 
       Loop Until Not blnFound 
      Case vbDate 
       If dtmTemp = adtmDates Then 
        dtmTemp = dtmTemp + intIncrement 
       End If 
     End Select 
    Loop Until Not IsWeekend(dtmTemp) 

ExitHere: 
    SkipHolidaysA = dtmTemp 
    Exit Function 

HandleErrors: 
    ' No matter what the error, just 
    ' return without complaining. 
    ' The worst that could happen is that we 
    ' include a holiday as a real day, even if 
    ' it's in the array. 
    Resume ExitHere 

End Function 
Private Function IsWeekend(dtmTemp As Variant) As Boolean 
    ' If your weekends aren't Saturday (day 7) and Sunday (day 1), 
    ' change this routine to return True for whatever days 
    ' you DO treat as weekend days. 

    ' Modified from code in "Visual Basic Language Developer's Handbook" 
    ' by Ken Getz and Mike Gilbert 
    ' Copyright 2000; Sybex, Inc. All rights reserved. 

    ' Required by: 
    ' SkipHolidays 
    ' dhFirstWorkdayInMonth 
    ' dbLastWorkdayInMonth 
    ' dhNextWorkday 
    ' dhPreviousWorkday 
    ' dhCountWorkdays 

    If VarType(dtmTemp) = vbDate Then 
     Select Case WeekDay(dtmTemp) 
      Case vbSaturday, vbSunday 
       IsWeekend = True 
      Case Else 
       IsWeekend = False 
     End Select 
    End If 
End Function 

Private Function FindItemInArray(varItemToFind As Variant, _ 
avarItemsToSearch As Variant) As Boolean 
    Dim lngItem As Long 

    On Error GoTo HandleErrors 

    For lngItem = LBound(avarItemsToSearch) To UBound(avarItemsToSearch) 
     If avarItemsToSearch(lngItem) = varItemToFind Then 
      FindItemInArray = True 
      GoTo ExitHere 
     End If 
    Next lngItem 

ExitHere: 
    Exit Function 

HandleErrors: 
    ' Do nothing at all. 
    ' Return False. 
    Resume ExitHere 
End Function 
+0

감사합니다. 이것은 작동해야합니다, 이제는 Excel에서 작동하도록 수정하고 시간도 계산해야합니다. –

+0

그 대답을 받아 들일 수 있겠습니까? –

+0

조금 늦었지만 그것을 받아 들였습니다. 도와 주셔서 감사합니다 –