Home > Blockchain >  How to calculate the start time and end time of a jobs using VBA code?
How to calculate the start time and end time of a jobs using VBA code?

Time:10-31

I am trying to recreate this below calculation in VBA code and I would like it to be output to a worksheet imagine that the column title 'processing time' starts from B4:

Processing Time Start Time End Time Start Time Current Formula End Time Current Formula
8 0 8 0 C5 B5 (0 8)
7 8 15 C5 B5 (0 8) C6 B6 (8 7)
6 15 21 C6 B6 (8 7) C7 B7 (15 6)
6 21 27 C7 B7 (15 6) C8 B8 (21 6)

How would I go about getting these calculations on a new sheet using VBA code? To add a bit of context, I have a whole bunch of code that solves a scheduling problem - i.e., distributing jobs to mechanics it is essentially a bin packing problem of how many jobs can be given to any one mechanic at a time, assuming there is an 8 hour day. What you see above is a snippet of processing times for each job. So far I have no code for this part of the tool as I was unclear on where to start especially to make it dynamic

The requirement of this tool is that everything is done in VBA which is why I am not just using spreadsheet functions, which of course would be far simpler!

The second part of my question relates to being able to show the jobs that weren't able to be scheduled, both as a list on sheet "Schedule" column F and also has a message box to the user when they run the schedule. The part of the code in question is in the section 'implement pseudocode' where I have an else statement that is commented out. Please see me code below:

Option Explicit

Type jobData
    jobID As Long
    processingTime As Double
End Type

Type mechanicData
    availableHours As Double                        'This takes into consideration the amount of workable hours per day
    remainingAvailableHours As Double               'This decreases as more jobs are added on to each mechanics workload
    jobsToMechanic() As Long                        'Record the jobs to each mechanic
    makeSpan As Long                                'How many hours the each mechanic has used so far
End Type

Sub ScheduleMechanics()

    'Define problem size variables
    
    Dim numJobs As Long
    Dim numMechanics As Long
    
    'Read data
    
    ThisWorkbook.Worksheets("Data").Activate
    
    numJobs = Cells(1, 2).Value                     'How many jobs are in sequence
    numMechanics = Cells(2, 2).Value                'How many mechanics are available
    
    'Sort processing time data from worksheet
    
    Range(Cells(4, 1).Address & ":" & Cells(4   numJobs, 2).Address).Select
    ActiveWorkbook.Worksheets("Data").Sort.SortFields.Clear
    ActiveWorkbook.Worksheets("Data").Sort.SortFields.Add2 Key:=Range(Cells(5, 2).Address & ":" & Cells(4   numJobs, 2).Address) _
        , SortOn:=xlSortOnValues, Order:=xlDescending, DataOption:=xlSortNormal
    With ActiveWorkbook.Worksheets("Data").Sort
        .SetRange Range(Cells(4, 1).Address & ":" & Cells(4   numJobs, 2).Address)
        .Header = xlYes
        .MatchCase = False
        .Orientation = xlTopToBottom
        .SortMethod = xlPinYin
        .Apply
    End With
    
    'Error handling for Item ID and size
    
    Range(Cells(5, 1).Address & ":" & Cells(5   numJobs   1, 2).Address).Select
    With Selection.Validation
        .Delete
        .Add Type:=xlValidateWholeNumber, AlertStyle:=xlValidAlertStop, _
        Operator:=xlGreaterEqual, Formula1:="0"
        .IgnoreBlank = False
        .InCellDropdown = True
        .InputTitle = ""
        .ErrorTitle = "Error"
        .InputMessage = ""
        .ErrorMessage = "Please enter numerical values only."
        .ShowInput = True
        .ShowError = True
    End With
    
    Dim jobList() As jobData
    ReDim jobList(1 To numJobs)

    
    Dim i As Long                                                   'Loop counter 1
    
    For i = 1 To numJobs
        jobList(i).jobID = Cells(4   i, 1).Value                    'Determining processing time
        jobList(i).processingTime = Cells(4   i, 2).Value
    Next i
    
    Dim Mechanic() As mechanicData
    ReDim Mechanic(1 To numMechanics)
    
    For i = 1 To numMechanics
        Mechanic(i).availableHours = Cells(3, 2).Value
    Next i
    
    'Initialise the solution where all mechanics have an empty schedule with a makespan of 0
    
    For i = 1 To numMechanics
        Mechanic(i).remainingAvailableHours = Mechanic(i).availableHours
        Mechanic(i).makeSpan = 0
        ReDim Mechanic(i).jobsToMechanic(1 To numJobs)
    Next i
    
    'Implement pseudocode
    
    Dim j As Long                                                    'Loop counter 2
    Dim minMakespan As Long
    Dim mechanicSelected As Long
    
    For i = 1 To numJobs

        minMakespan = 9
        mechanicSelected = 0

            For j = 1 To numMechanics

                If Mechanic(j).makeSpan < minMakespan And _
                    Mechanic(j).makeSpan   jobList(i).processingTime <= Mechanic(j).availableHours Then
                    mechanicSelected = Mechanic(j).remainingAvailableHours
                    minMakespan = Mechanic(j).makeSpan
                End If


                'if job i fits in mehcanic j's schedule then
                If jobList(i).processingTime <= Mechanic(j).remainingAvailableHours Or _
                mechanicSelected > 0 Then

                    'place job i in mechanic j's schedule and update the makespan of mechanicSelected
                    Mechanic(j).makeSpan = Mechanic(j).makeSpan   1
                    Mechanic(j).jobsToMechanic(Mechanic(j).makeSpan) = jobList(i).jobID
                    Mechanic(j).remainingAvailableHours = Mechanic(j).remainingAvailableHours - jobList(i).processingTime
                'Else
                    'Report job i as unfeasible to scheduled on day
                    'MsgBox "Job ID " & jobList(i).jobID & " is unfeasible to be scheduled on this day", vbInformation, "Information"

                    Exit For

                End If

            Next j

        Next i
        
    'Lets the user know the algorithm is completed
    MsgBox "Algorithm Completed.", vbInformation, "Success!"

    
    'Write the result
    
    ThisWorkbook.Worksheets("Schedule").Activate
    
    'Erase before writing
    
    Columns("A:J").ClearContents
    
    Dim rowIndex As Long
    Dim startTime As Integer
    Dim endtime As Integer
    
    rowIndex = 1
    startTime = 0

    
    For i = 1 To numJobs
        jobList(i).processingTime = Cells(4   i, 2).Value
    Next i
    
    'Naming column names
    
    Cells(1, 1).Value = "Mechanic"
    Cells(1, 2).Value = "Job ID"
    Cells(1, 3).Value = "Job Processing Time"
    Cells(1, 4).Value = "Start Time (Hrs)"
    Cells(1, 5).Value = "End Time (Hrs)"
    Cells(1, 6).Value = "Unscheduled Jobs"
    
    Rows("1").Select
    Selection.Font.Bold = True
    
    rowIndex = rowIndex   1
    
    For j = 1 To numMechanics
        Cells(rowIndex, 1).Value = "Mechanic " & j
        
        For i = 1 To Mechanic(j).makeSpan
            Cells(rowIndex, 2).Value = "Job " & Mechanic(j).jobsToMechanic(i)
            Cells(rowIndex, 3).Value = Application.WorksheetFunction.vLookup _
            (Mechanic(j).jobsToMechanic(i), ThisWorkbook.Worksheets("Data").Columns("A:B"), 2, False) & "hrs"
            If Mechanic(j).jobsToMechanic(i) = 1 Then
                Cells(rowIndex, 4).Value = startTime
                Else
                Cells(rowIndex, 4).Value = startTime   jobList(i).processingTime
            End If
            'Cells(rowIndex, 5).Value =
            rowIndex = rowIndex   1
        Next i
        rowIndex = rowIndex   1
    Next j
    
    'AutoFit All Columns on Worksheet
    ThisWorkbook.Worksheets("Schedule").Cells.EntireColumn.AutoFit
    
    'Housekeeping
    
    Erase jobList
    Erase Mechanic
     
End Sub

When I uncomment out my 'else' statement the results are then incorrect and the message box just shows me all the jobs that are actually scheduled but as individual message boxes rather than a list within the same message box.

My desired result is to be able to show the list of unscheduled jobs and also a message box. I've been stuck on this for days, I am sure there is something super simple that I have failed to do, but any help would be so appreciated :)

Thank you!!

CodePudding user response:

I have added mechanic to jobData to identify unallocated jobs.

Option Explicit

Type jobData
    jobID As Long
    processingTime As Double
    mechanic As Long
End Type

Type mechanicData
    availableHours As Double           'This takes into consideration the amount of workable hours per day
    remainingAvailableHours As Double  'This decreases as more jobs are added on to each mechanics workload
    jobsToMechanic() As Long           'Record the jobs to each mechanic
    makeSpan As Long                   'How many jobs a mechanic has so far
End Type

Sub ScheduleMechanics()

    'Define problem size variables
    Dim numJobs As Long
    Dim numMechanics As Long
    
    'Read data
    With ThisWorkbook.Worksheets("Data")
    
        numJobs = .Cells(1, 2).Value      'How many jobs are in sequence
        numMechanics = .Cells(2, 2).Value  'How many mechanics are available
        
        'Sort processing time data from worksheet
        .Sort.SortFields.Clear
        .Sort.SetRange .Range("A4:B" & 4   numJobs)
        .Sort.SortFields.Add Key:=.Range("B4"), SortOn:=xlSortOnValues, _
           Order:=xlDescending, DataOption:=xlSortNormal
        With .Sort
            .Header = xlYes
            .MatchCase = False
            .Orientation = xlTopToBottom
            .SortMethod = xlPinYin
            .Apply
        End With
        
        'Error handling for Item ID and size
        With .Range("A5:B" & numJobs - 1).Validation
            .Delete
            .Add Type:=xlValidateWholeNumber, AlertStyle:=xlValidAlertStop, _
            Operator:=xlGreaterEqual, Formula1:="0"
            .IgnoreBlank = False
            .InCellDropdown = True
            .InputTitle = ""
            .ErrorTitle = "Error"
            .InputMessage = ""
            .ErrorMessage = "Please enter numerical values only."
            .ShowInput = True
            .ShowError = True
        End With
        
        Dim jobList() As jobData
        ReDim jobList(1 To numJobs)
        Dim i As Long
        For i = 1 To numJobs
            jobList(i).jobID = .Cells(4   i, 1).Value
            jobList(i).processingTime = .Cells(4   i, 2).Value
            jobList(i).mechanic = 0
        Next
    
        Dim mechanic() As mechanicData
        ReDim mechanic(1 To numMechanics)
        'Initialise the solution where all mechanics have an empty schedule
        'with a makespan of 0
        For i = 1 To numMechanics
            mechanic(i).availableHours = .Cells(3, 2).Value
            mechanic(i).remainingAvailableHours = mechanic(i).availableHours
            mechanic(i).makeSpan = 0
            ReDim mechanic(i).jobsToMechanic(1 To numJobs)
        Next

    End With
    
    'Implement pseudocode
    Dim j As Long, msg As String                                                    'Loop counter 2
    Dim minMakespan As Long
    Dim mechanicSelected As Long
        
    For i = 1 To numJobs
        mechanicSelected = 0
        For j = 1 To numMechanics

            'if job i fits in mehcanic j's schedule then
            If jobList(i).processingTime <= mechanic(j).remainingAvailableHours Then
                mechanicSelected = j
                jobList(i).mechanic = i
                'place job i in mechanic j's schedule and update the makespan of mechanicSelected
                mechanic(j).makeSpan = mechanic(j).makeSpan   1
                mechanic(j).jobsToMechanic(mechanic(j).makeSpan) = i
                mechanic(j).remainingAvailableHours = mechanic(j).remainingAvailableHours - jobList(i).processingTime
                Exit For
            End If
            
        Next j
        
        If mechanicSelected = 0 Then
            msg = msg & vbLf & jobList(i).jobID _
            & " (" & jobList(i).processingTime & " hrs}"
        End If
    Next i
    
    'Lets the user know the algorithm is completed
    If Len(msg) > 0 Then
        MsgBox "Not able to scheduled these jobs : " & msg, _
        vbExclamation, "Failure"
    Else
        MsgBox "Algorithm Completed.", vbInformation, "Success!"
    End If
    
    'Write the result
    Dim rowIndex As Long
    Dim startTime As Integer
    Dim endTime As Integer
    Dim job As jobData
    
    With ThisWorkbook.Worksheets("Schedule")
    
        'Erase before writing
        .Columns("A:J").ClearContents
        
        'Naming column names
        .Cells(1, 1).Value = "Mechanic"
        .Cells(1, 2).Value = "Job ID"
        .Cells(1, 3).Value = "Job Processing Time"
        .Cells(1, 4).Value = "Start Time (Hrs)"
        .Cells(1, 5).Value = "End Time (Hrs)"
        .Cells(1, 6).Value = "Unscheduled Jobs"
        .Rows("1").Font.Bold = True
        
        rowIndex = 2
        
        For j = 1 To numMechanics
            .Cells(rowIndex, 1).Value = "Mechanic " & j
            
            For i = 1 To mechanic(j).makeSpan
                job = jobList(mechanic(j).jobsToMechanic(i))
                .Cells(rowIndex, 2).Value = "Job " & job.jobID
                .Cells(rowIndex, 3).Value = job.processingTime & " hrs"
                If i = 1 Then
                    startTime = 0
                End If
                endTime = startTime   job.processingTime
                .Cells(rowIndex, 4).Value = startTime
                .Cells(rowIndex, 5).Value = endTime
                rowIndex = rowIndex   1
                startTime = endTime ' next job
            Next i
            rowIndex = rowIndex   1
        Next j
        
        ' unscheduled jobs
        rowIndex = 1
        For i = 1 To numJobs
            If jobList(i).mechanic = 0 Then
                rowIndex = rowIndex   1
                .Cells(rowIndex, 6) = jobList(i).jobID _
                & " (" & jobList(i).processingTime & " hrs)"
            End If
        Next
        'AutoFit All Columns on Worksheet
        .Columns("A:J").EntireColumn.AutoFit
        .Activate
        .Range("A1").Select
    End With
    MsgBox "Done"
    'Housekeeping
    Erase jobList
    Erase mechanic
     
End Sub
  • Related