Question : how to calculate buisness day : hours : including saturdays and excluding public holidays ,lunch break and sunday

i want a macro that calculates elapsed business time between a start date and end date in dd:hh:mm:ss format in MS EXCEL keeping the following parameters in mind

1) should exclude lunch break start of which is indicated in aw2 and end time in ax 2 .there can be multiple breaks which can be indicated in the columns aw and ax .
2) should have the flexibility of including or excluding Saturday and sunday as a workday .
3) should have the flexibility of excluding public holidays .

Answer : how to calculate buisness day : hours : including saturdays and excluding public holidays ,lunch break and sunday

debashish_mukherji,

The code below seems to be doing what you want.

Patrick
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
Function WorkingHrs(StartAt As Date, EndAt As Date, Optional WorkStart As Date = #9:00:00 AM#, _
    Optional WorkEnd As Date = #5:00:00 PM#, Optional Workdays As String = "23456", _
    Optional Holidays As Variant, Optional Breaks As Variant)
    
    ' Function calculates working hours available within a specified datetime range, allowing for
    ' scheduled working hours, non-working days, and holidays (if desired)
    
    ' Workdays specifies days employees normally work.  For example, to use Mon - Fri, use 23456.
    ' To do just Tue & Thu, use 35; etc.
    
    ' assumes scheduled working hrs are the same on each working day!
    
    Dim Counter As Long
    Dim Dict As Object
    Dim x As Variant
    Dim y As Variant
    Dim Days(1 To 7) As Boolean
    Dim WorkThisDay As Boolean
    Dim HolThisDay As Boolean
    Dim DateToday As Date
    Dim DayStart As Date
    Dim DayEnd As Date
    Dim BreaksArr() As Date
    Dim DayLength As Date
    Dim WorkParts(1 To 4) As Long
    
    ' array indicates whether that weekday is a regular workday.  Initialize to False
    Days(1) = False
    Days(2) = False
    Days(3) = False
    Days(4) = False
    Days(5) = False
    Days(6) = False
    Days(7) = False
    
    ' populate array with results from Workdays argument
    For Counter = 1 To Len(Workdays)
        Days(Val(Mid(Workdays, Counter, 1))) = True
    Next
    
    'On Error GoTo Cleanup
    
    ' populate holiday array
    If Not IsMissing(Holidays) Then
        Set Dict = CreateObject("Scripting.Dictionary")
        For Each x In Holidays
            For Each y In x
                If Not Dict.Exists(Format(y, "m/d/yyyy")) Then Dict.Add Format(y, "m/d/yyyy"), Format(y, "m/d/yyyy")
            Next
        Next
    End If
        
    ' populate Breaks array
    If Not IsMissing(Breaks) Then
        ReDim BreaksArr(0) As Date
        For Each x In Breaks
            If UBound(BreaksArr) = 0 Then
                ReDim BreaksArr(1 To 1) As Date
                BreaksArr(1) = x
            Else
                ReDim Preserve BreaksArr(1 To UBound(BreaksArr) + 1)
                BreaksArr(UBound(BreaksArr)) = x
            End If
        Next
    End If
    
    'loop through days in datetime range
    For Counter = Int(StartAt) To Int(EndAt)
        DateToday = CDate(Counter)
        ' determine if regular workday
        WorkThisDay = Days(Weekday(DateToday, vbSunday))
        ' determine if holiday
        If IsMissing(Holidays) Then
            HolThisDay = False
        Else
            If Dict.Exists(Format(DateToday, "m/d/yyyy")) Then HolThisDay = True Else HolThisDay = False
        End If
        ' if regular workday and not a holiday, figure out hrs from that day
        If WorkThisDay And Not HolThisDay Then
            ' starts and ends on same day
            If Int(StartAt) = Int(EndAt) Then
                DayStart = IIf(CDate(StartAt - Int(StartAt)) > WorkStart, CDate(StartAt - Int(StartAt)), WorkStart)
                DayEnd = IIf(CDate(EndAt - Int(EndAt)) < WorkEnd, CDate(EndAt - Int(EndAt)), WorkEnd)
                WorkingHrs = IIf(CDbl(DayEnd - DayStart) < 0, 0, CDbl(DayEnd - DayStart))
            ' first day, if first day <> last day
            ElseIf Counter = Int(StartAt) Then
                DayStart = IIf(CDate(StartAt - Int(StartAt)) > WorkStart, CDate(StartAt - Int(StartAt)), WorkStart)
                DayEnd = WorkEnd
                WorkingHrs = IIf(CDbl(DayEnd - DayStart) < 0, 0, CDbl(DayEnd - DayStart))
            ' days in between start and end, if any
            ElseIf Counter > Int(StartAt) And Counter < Int(EndAt) Then
                DayStart = WorkStart
                DayEnd = WorkEnd
                WorkingHrs = WorkingHrs + CDbl(WorkEnd - WorkStart)
            ' last day, if first day <> last day
            ElseIf Counter = Int(EndAt) Then
                DayStart = IIf(CDate(EndAt - Int(EndAt)) > WorkStart, WorkStart, CDate(EndAt - Int(EndAt)))
                DayEnd = IIf(CDate(EndAt - Int(EndAt)) < WorkEnd, CDate(EndAt - Int(EndAt)), WorkEnd)
                WorkingHrs = WorkingHrs + IIf(CDbl(DayEnd - DayStart) < 0, 0, CDbl(DayEnd - DayStart))
            End If
            If Not IsMissing(Breaks) Then
                For x = 1 To UBound(BreaksArr) - (UBound(BreaksArr) Mod 2) Step 2
                    ' Break outside working time
                    If BreaksArr(x + 1) < DayStart Or BreaksArr(x) > DayEnd Then
                        'do nothing
                    ' Break covers all of working time
                    ElseIf BreaksArr(x) < DayStart And BreaksArr(x + 1) > DayEnd Then
                        WorkingHrs = WorkingHrs - (DayEnd - DayStart)
                    ' Break fits inside working time
                    ElseIf DayStart <= BreaksArr(x) And DayEnd >= BreaksArr(x + 1) Then
                        WorkingHrs = WorkingHrs - (BreaksArr(x + 1) - BreaksArr(x))
                    ' Break starts before working time but does not extend beyond it
                    ElseIf BreaksArr(x) < DayStart Then
                        WorkingHrs = WorkingHrs - (BreaksArr(x + 1) - DayStart)
                    ' Break starts within working time but extends beyond it
                    Else
                        WorkingHrs = WorkingHrs - (DayEnd - BreaksArr(x))
                    End If
                Next
            End If
        End If
    Next
    
    DayLength = WorkEnd - WorkStart
    If Not IsMissing(Breaks) Then
        For x = 1 To UBound(BreaksArr) - (UBound(BreaksArr) Mod 2) Step 2
            ' Break outside working time
            If BreaksArr(x + 1) < WorkStart Or BreaksArr(x) > WorkEnd Then
                'do nothing
            ' Break covers all of working time
            ElseIf BreaksArr(x) < WorkStart And BreaksArr(x + 1) > WorkEnd Then
                DayLength = DayLength - (WorkEnd - WorkStart)
            ' Break fits inside working time
            ElseIf WorkStart <= BreaksArr(x) And WorkEnd >= BreaksArr(x + 1) Then
                DayLength = DayLength - (BreaksArr(x + 1) - BreaksArr(x))
            ' Break starts before working time but does not extend beyond it
            ElseIf BreaksArr(x) < WorkStart Then
                DayLength = DayLength - (BreaksArr(x + 1) - WorkStart)
            ' Break starts within working time but extends beyond it
            Else
                DayLength = DayLength - (WorkEnd - BreaksArr(x))
            End If
        Next
    End If
    
    ' convert days to hours
    'WorkingHrs = WorkingHrs * 24
    Debug.Print Format(WorkingHrs, "[h]:mm:ss")
    WorkParts(1) = Int(CDbl(WorkingHrs) / CDbl(DayLength))
    WorkingHrs = WorkingHrs - WorkParts(1) * DayLength
    WorkParts(2) = Hour(WorkingHrs)
    WorkingHrs = WorkingHrs - TimeSerial(WorkParts(2), 0, 0)
    WorkParts(3) = Minute(WorkingHrs)
    WorkingHrs = WorkingHrs - TimeSerial(0, WorkParts(3), 0)
    WorkParts(4) = Second(WorkingHrs)
    
    WorkingHrs = ""
    If WorkParts(1) = 1 Then
        WorkingHrs = "1 day"
    ElseIf WorkParts(1) > 1 Then
        WorkingHrs = WorkParts(1) & " days"
    End If
    If WorkingHrs <> "" And WorkParts(2) > 0 Then WorkingHrs = WorkingHrs & " "
    If WorkParts(2) = 1 Then
        WorkingHrs = WorkingHrs & "1 hour"
    ElseIf WorkParts(2) > 1 Then
        WorkingHrs = WorkingHrs & WorkParts(2) & " hours"
    End If
    If WorkingHrs <> "" And WorkParts(3) > 0 Then WorkingHrs = WorkingHrs & " "
    If WorkParts(3) = 1 Then
        WorkingHrs = WorkingHrs & "1 minute"
    ElseIf WorkParts(3) > 1 Then
        WorkingHrs = WorkingHrs & WorkParts(3) & " minutes"
    End If
    If WorkingHrs <> "" And WorkParts(4) > 0 Then WorkingHrs = WorkingHrs & " "
    If WorkParts(4) = 1 Then
        WorkingHrs = WorkingHrs & "1 second"
    ElseIf WorkParts(4) > 1 Then
        WorkingHrs = WorkingHrs & WorkParts(4) & " seconds"
    End If
    
Cleanup:
    On Error GoTo 0
    Set Dict = Nothing
    
End Function
Random Solutions  
 
programming4us programming4us