Cannot think of a short title, see whole post please :)

Lux Aeterna

Board Regular
Joined
Aug 27, 2015
Messages
191
Office Version
  1. 2019
Platform
  1. Windows
I've made an excel sheet that automatically adds working hours (arrival - departure) and overtime hours for every month.

What I'd like to do is to add overtime up to 20 hours per month in total.

In the picture below there are 22 working days, so I'd like to have a maximum of 20 days of 1 hour overtime, not 22 as it is now (yellow box).

Moreover, there are months that someone might work, for example, for 15 days. So a possible solution would be 10 days of 1 hour overtime and 5 days of 2 hours overtime.

Finally, someone might have worked for 8 days. In that case I'd like to have 2 hours overtime daily.

Max overtime per day is 2 hours, and max overtime per month is 20 hours.

Hope it's not too complicated, thank toy in advance.

PS: Wherever you see 15:00, it's the sum of the cell on the left (14:00) plus 1:00. I can add the excel file if necessary

1637680752152.png
 
Would the following work?

1642255293566.png


When you are happy, hide the yellow rows.
Formula's:
B5: =IF(C4-B4,IF((C4-B4)<7/24,1,2),0)
D5: =IF(E4-D4,IF(SUM($B5:C5)<20,MIN(2,20-SUM($B5:C5)),0),0)
Copy D5 to F5, H5 and J5
L5: =SUM(B5:K5)

B6: =IF(B5,C4,"-")
C6: =IF(B5,B6+B5/24,"-")
Copy B6:C6 to all other overtime cells (green cells)

B11: =IF(C10-B10,IF($L5<20,MIN(2,20-$L5),0),0)
D11: =IF(E10-D10,IF(SUM($B11:C11,$L5)<20,MIN(2,20-SUM($B11:C11)),0),0)
Copy D11 to F11, H11 and J11
L11: =SUM(B5:K5,L5)
Copy D11:L11 to rows 17, 23 & 29
 
Upvote 0

Excel Facts

Copy PDF to Excel
Select data in PDF. Paste to Microsoft Word. Copy from Word and paste to Excel.
@sijpie

It works great, but only when all days are filled in. For example, Tuesday 4 is a day off (it could be an illness or a holiday or several other "no-work" reasons) and I get those VALUE messages. Moreover, all days after the "no-work" day show the VALUE error. I also get VALUE messages on the last 4 boxes, although in your sheet it seems to be working fine.

L11: =SUM(B5:K5,L5)
I think this should be B11:K11.

=IF(C4-B4,IF((C4-B4)<7/24,1,2),0)

=IF(E4-D4,IF(SUM($B5:C5)<20,MIN(2,20-SUM($B5:C5)),0),0)
I'd rather prioritise 1 hour overtime, so I just swapped 1 and 2 [ Formula now is =IF(C4-B4,IF((C4-B4)<7/24,2,1),0) ] and replaced 2 to 1 in all other formulas. Seems to be working so far, but if someone works for 18 days, it won't adjust to 20 hours of overtime.

Finally, when there's an evening shift Overtime departure (yellow box) cannot be later than 22:00.

I suppose what I'm asking for is crazy difficult, and I'm really grateful for al your help so far!

PS. If LET function is easier for it, I might be able to upgrade to Office 2021.

1643162611000.png
 
Last edited by a moderator:
Upvote 0
The following should do it. The formula's are fairly complicated but it works...

Formula's:
B5: =IFERROR(IF(C4-B4,MIN(2,IF(C4*24<22,22-C4*24)),0),0)
D5: ==IFERROR(IF(E4-D4,MIN(2,IF(E4*24<22,22-E4*24)),0),0)
Copy D5 to F5, H5 and J5
L5: =SUM(B5:K5)

B6: =IF(B5,IF(C4<22/24,C4,"-"),"-")
C6: =IF(B5,B6+B5/24,"-")
Copy B6:C6 to all other overtime cells (green cells)

B11: =IFERROR(IF(C10-B10,IF($L5<20,MIN(2,20-$L5,IF(C10*24<22,22-C10*24)),0),0),0)
D11: =IFERROR(IF(E10-D10,MIN(2,MAX(0,20-SUM($B11:C11,$L5)),IF(E10*24<22,22-E10*24)),0),0)
Copy D11 to F11, H11 and J11
L11: =SUM(B5:K5,L5)
Copy B11:L11 to rows 17, 23 & 29

1643724298381.png
 
Upvote 0
Solution
The following should do it. The formula's are fairly complicated but it works...
Hey!

I just managed to check it and it works flawlessly!
I only corrected L11: =SUM(B11:K11,L5) and changed departure time to 21:00 (instead of 22:00)

Would you mind me asking for a last adaptation? I'd rather have OT hours more evenly distributed, in order to not have days with 0 hours of OT (yellow) and days with 2 hours of OT (orange). Ideally, there should be as many 1 hour OT as possible (max 20 hours per month) and as few 2 hour OT as needed to sum up to 20 (if 1 hour OT are not enough for it). If that's not easy, don't bother! :)

1646691615707.png
 
Upvote 0
In order to do that I think I would need to write a macro. Trying to do this with formulas is difficult, because it will create a circular formula. I don't know if you want to use a macro. The macro would work automatically in the background, but the first time you will need to allow the macro to run. Some companies don't like excel workbooks with macro's.
 
Upvote 0
In order to do that I think I would need to write a macro. Trying to do this with formulas is difficult, because it will create a circular formula. I don't know if you want to use a macro. The macro would work automatically in the background, but the first time you will need to allow the macro to run. Some companies don't like excel workbooks with macro's.
Using a macro is fine! That's not a company project. I use the excel file on my own computer, to save colleagues from wasting their time in bureaucratic nonsense :)
 
Upvote 0
OK. it is a bit longwinded code, but it should work.

  1. Save the workbook as .xlsm Macro enabled
  2. On your month overtime sheet, right click the sheet name tab and select View code..
  3. This opens the codemodule for the sheet, where you can intercept things done to the sheet. You want to intercept any modifications made.
  4. In the module paste the following code.
  5. Then check the comments at the top. If B2 is not the top left cell (Monday) then let me know!!
When you make a new month, make a copy of this current month, so that the code is copied as well and works for the new month

VBA Code:
Option Explicit

Private Sub Worksheet_Change(ByVal Target As Range)
    ' This macro runs on any value change made to worksheet
    'It assumes the top left cell 'Monday' is cell B2
    
    Dim rTotOT As Range
    Dim iTot As Integer, iR As Integer, iC As Integer, iRC As Integer, iCC As Integer, _
        UB1 As Integer, UB2 As Integer, iDepHr As Integer, iCurOT As Integer, iROffs As Integer, iCOffs As Integer
    Dim vMonth As Variant
    Dim bDepTime As Boolean
    Dim colOT1hr As Collection, colOT2hr As Collection
    Dim vDate As Variant
    
    'if more than 1 cell changed (copy paste for instance) then exit
    If Target.Cells.Count > 1 Then Exit Sub
    
    ' check if relevant cell has changed. The cell changed is called 'Target'
    If Not Intersect(Target, Union(Range("B4:K4"), Range("B10:K10"), Range("B16:K16"), Range("B22:K22"), Range("B28:K28"))) Is Nothing Then
        ' is arrival or departure time changed?
        bDepTime = Target.Column Mod 2
        ' only act on changes when both start and departure time are given
        If (bDepTime And Target < Target.Offset(0, -1)) Or (Not bDepTime And Target > Target.Offset(0, 1)) Then
        ' if OT exists, but deptime < arr time, then clear OT
            If bDepTime Then
                Target.Offset(1, -1) = 0
            Else
                Target.Offset(1, 0) = 0
            End If
            Exit Sub
        End If
        
        If (bDepTime And Target > Target.Offset(0, -1)) Or (Not bDepTime And Target < Target.Offset(0, 1)) Then
            'initiate two collections to keep score of 1hr and 2 hour overtime allocations
            Set colOT1hr = New Collection: Set colOT2hr = New Collection
            
            vMonth = Range("B2:K30").Value
            iROffs = 1: iCOffs = 1      '   With cell B2 being Monday, offset between array and sheet is 1 column and 1 row
            UB1 = UBound(vMonth, 1): UB2 = UBound(vMonth, 2)
            iRC = Target.Row - iROffs: iCC = Target.Column - iCOffs
            ' get total OT already assigned
            For iR = 4 To UB1 Step 6
                For iC = 1 To UB2 Step 2
                    Select Case vMonth(iR, iC)
                        Case 1
                            colOT1hr.Add iR & "," & iC
                        Case 2
                            colOT2hr.Add iR & "," & iC
                        Case Else   'do nothing
                    End Select
                Next iC
            Next iR
            'total overtime allocated
            iTot = colOT1hr.Count + colOT2hr.Count * 2
            
            'store any current OT in modified day
            iCurOT = IIf(bDepTime, vMonth(iRC + 1, iCC - 1), vMonth(iRC + 1, iCC))
            'check if dep < 22:00
            If bDepTime Then
                iDepHr = CInt(vMonth(iRC, iCC) * 24)
            Else
                iDepHr = CInt(vMonth(iRC, iCC + 1) * 24)
            End If
            'now see what OT needs to be added
            iTot = iTot - iCurOT  '(-current ot as this may be a change of arrival or departure time)
            Select Case iTot
                Case Is <= 18
                    Select Case iDepHr
                        Case Is >= 22
                            ' too late to claim OT
                        Case 21
                            ' One hour possible
                            'add 1 hr OT to date's OT line
                            If bDepTime Then
                                Target.Offset(1, -1) = 1
                            Else
                                Target.Offset(1, 0) = 1
                            End If
                        Case Else
                            ' Two hours possible
                            'add 2 hr OT to date's OT line
                            If bDepTime Then
                                Target.Offset(1, -1) = 2
                            Else
                                Target.Offset(1, 0) = 2
                            End If
                    End Select
                Case 19
                    Select Case iDepHr
                        Case Is >= 22
                            ' too late to claim OT
                        Case Else
                            ' One hour possible
                            'add 1 hr OT to date's OT line
                            If bDepTime Then
                                Target.Offset(1, -1) = 1
                            Else
                                Target.Offset(1, 0) = 1
                            End If
                    End Select
                Case 20
                    Select Case iDepHr
                        Case Is >= 22
                            ' too late to claim OT
                        Case Else
                            ' One hour possible but need to decrease any 2hr OT
                            If colOT2hr.Count > 0 Then
                                'adjust 1st 2 hr OT to 1 hr
                                vDate = Split(colOT2hr(1), ",")
                                Cells(vDate(0) + iROffs, vDate(1) + iCOffs) = 1
                                'add 1 hr OT to date's OT line
                                If bDepTime Then
                                    Target.Offset(1, -1) = 1
                                Else
                                    Target.Offset(1, 0) = 1
                                End If
                            Else
                                ' no OT available, all already as 1 hr
                                If bDepTime Then
                                    Target.Offset(1, -1) = 0
                                Else
                                    Target.Offset(1, 0) = 0
                                End If
                            End If
                    End Select
            End Select
        End If
    End If
End Sub
 
Upvote 0
OK. it is a bit longwinded code, but it should work.

  1. Save the workbook as .xlsm Macro enabled
  2. On your month overtime sheet, right click the sheet name tab and select View code..
  3. This opens the codemodule for the sheet, where you can intercept things done to the sheet. You want to intercept any modifications made.
  4. In the module paste the following code.
  5. Then check the comments at the top. If B2 is not the top left cell (Monday) then let me know!!
When you make a new month, make a copy of this current month, so that the code is copied as well and works for the new month
Hey again!

B2 (actually it's B8 on my sheet) is always Monday, but sometimes it's left empty, because it's not the first day of the month (for example, on March 2022 the first day is Tuesday, which is on cell D8, April the 1st is Friday on J8 and so on), or it's a day off, leave of absence etc.

I use the same sheet for every month (I just change the date), because all the leaves of absence of the year are registered there.
 
Upvote 0

Forum statistics

Threads
1,214,620
Messages
6,120,559
Members
448,970
Latest member
kennimack

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top