These docs are for v1.1. Click to read the latest docs for v2.0.

Shift Scheduling

Creating shifts and assigning them to employees in 1 go.

Creating an optimal roster for a team of employees based on forecasted demand and taking into account extensive labor agreement rules & constraints.

  • Based on last weeks sales, last planning, predicted weather, revenue and reservations, a clear demand can be generated used as base occupation per skill, per location, per time block.
  • Collective Work Agreements are numerous and complex. Our optimisation already takes into account hundreds of specific employee constraints. Not enough? Simply create your own work rules.
  • Not only automagically generate a plan in seconds, but define what is important in the optimisation. Is financial wage cost minimisation more important than fairness? It's just a parameter. Our advanced mathematical solver engine can handle any request.

Input

Shift scheduling is about fairly distributing shifts among employees according to capacity requirements, specialism constraints, preferences, shift types and CAO agreements.

{
  "solver": "SHIFT",
  "demand": [ ... ],
  "employees": [ ... ],
  "options": {
    "shiftBlocksPerDay": 24
  }
}

The structure of a basic workforce planning model is as follows:

PropertyValue
demandArray of Shift Demands
statutesArray of Statutes
employeesArray of Employees
optionsA list of options for the scheduling problem

Shift Demands

{
  "shift": {
    ...
  },
  "skill": "Kitchen"
  "prefDemand": 2,
  "minDemand": 1,
  "maxDemand": 3
}

The list of shift demands represents the workstation/skill shift blocks to which it is required/necessary to assign (an) employee(s).

PropertyValueDescriptionRequired
shiftShift Blockthe shift block objectRequired
skillStringthe skill/workstationRequired
prefDemandIntegerthe preferred demand for that shift blockRequired
minDemandintegerthe minimal demand for that shift blockOptional
maxDemandintegerthe maximal demand for that shift blockOptional

Shift Blocks

{
  "date": "2018-11-14",
  "index": 0,
}

A shift block object consists of a date and a unique index for that block on that date. In combination with the number of shift blocks per day (see: Options), the user has full control of the detail/granularity of the demand profile that can be modeled. Please note, that an index larger than shiftBlocksPerDay can be provided: to model demand from the day after that should logically by filled in with shifts starting this day. E.g. an index 26 (with "shiftBlocksPerDay": 24) represents 01:00 of the following day.

PropertyValueDescriptionRequired
dateStringthe date of the shift block (in "YYYY-MM-DD")Required
indexIntegerthe index of the shift blockRequired

Statutes

{
  "name": "FIX",
  "minShiftLength": 3,
  "maxShiftLength": 11,
  "minRestBetweenShifts": 12,
  "maxConsecutiveWorkDays": 6,
  "maxHrsPerWeek": 50,
  "minHrsPerWeek": 10,
  "shiftStart": 0.0,
  "latestShiftStart": 24.0,
  "shiftEnd": 22.0,
  "minHoursMonth": 100,
  "maxHoursMonth": 200,
  "overTimeThreshold1": 9.0,
  "overTimeRaise1": 1.2,
  "overTimeThreshold2": 11.0,
  "overTimeRaise2": 1.5,
  "overTimeWeeklyThreshold1": 38,
  "overTimeWeeklyRaise1": 1.5,
  "nightlyThreshold1": 20.0,
  "nightlyRaise": 1.5
}

The list of statutes contain CAO specific parameters and the information with respect to the renumeration of the employees.

PropertyValueDescriptionRequired
nameStringthe name of a statues: e.g. "FIX", "PARTTIME", "STUDENT", ...Required
minShiftLengthIntegerThe minimum number of hours in a shift for an employeeRequired
maxShiftLengthIntegerThe maximum number of hours in a shift for this employeeRequired
minRestBetweenShiftsIntegerThe minimum duration (in hours) of a rest period between two shifts for this employeeRequired
maxConsecutiveWorkDaysIntegerThe maximum days consecutive that this employee can be workingRequired
maxHrsPerWeekIntegerThe maximum number of hours this employee can be working in a weekRequired
minHrsPerWeekIntegerThe minimum number of hours this employee should be working in a weekRequired
shiftStartDoubleThe earliest this employee can start working (expressed as decimal in 24 hour-format)Required
latestShiftStartDoubleThe latest this employee can start working (expressed as decimal in 24 hour-format)Required
shiftEndDoubleThe latest this employee can work on a day (expressed as decimal in 24 hour-format)Required
minHoursMonthIntegerThe minimum hours per month this employee should be workingRequired
maxHoursMonthIntegerThe maximum hours per month this employee should be workingRequired
overTimeThreshold1DoubleThe first time threshold for overtime (expressed as decimal in 24 hour-format)Required
overTimeRaise1DoubleThe raise after the first time threshold for overtime (e.q. 1.2 means a 20% raise per hour)Required
overTimeThreshold2DoubleThe second time threshold for overtime (expressed as decimal in 24 hour-format)Required
overTimeRaise2DoubleThe raise after the second time threshold for overtime (e.q. 1.2 means a 20% raise per hour)Required
overTimeWeeklyThreshold1IntegerThe number of hours per week after which a "weekly overtime" raise should be givenRequired
overTimeWeeklyRaise1DoubleThe weekly overtime raise (e.q. 1.2 means a 20% raise per hour)Required
nightlyThreshold1DoubleThe time threshold to be considered for a night raise (expressed as decimal in 24 hour-format)Required
nightlyRaiseDoubleThe raise after the first time threshold for overtime (e.q. 1.2 means a 20% raise per hour)Required

Employees

{
  "name": "E0",
  "statute": "FIX",
  "skill": [
    "Kitchen",
    "Restaurant",
  ],
  "hourlyPay": 11,
  "efficiency": 1,
  "preferences": [
        {
          "start": "2019-08-09T18:00:00",
          "end": "2019-08-10T02:00:00"
        }
      ],
  "hoursWorkedThisMonth": 0,
  "lastRestDate": "2019-03-04"
}

The employees to assign to the shift block demands are defined as follows.

PropertyValueDescriptionRequired
nameStringEmployee name or referenceRequired
statuteStringThe statute of the employeeRequired
skillArray of StringsThe skills/workstations this employee can manRequired
hourlyPayDoubleThe hourly wage for the employeeRequired
efficiencyDoubleThe efficiency of the employee: e.g. two new employees (efficiency: 0.5) are needed to replace an employee with more experienceRequired
preferencesArray of shift preference objectsThe preferred working hours for this employee.
hoursWorkedThisMonthIntegerThe number of hours this employee has already worked this monthRequired
lastRestDateDateThe date of last 36-hour rest period for this employee (in "YYYY-MM-DD")Required

Shift preferences

The shift preferences for the employees can be submitted using shift preference objects:

PropertyValueDescriptionRequired
startLocalDateTimeThe start of the preferred shiftRequired
endLocalDateTimeThe end of the preferred shiftRequired

|

Assignments

Assignments can be submitted in the solve request to the workforceplanning model for different reasons:

  • To fix certain pre-defined assignments (set "locked" : "true");
  • To set holidays, days-off or sick leave for an employee (set "locked" : "true" and set the skill of this assignment to a skill for which there is no demand given in the model, e.g. "skill" : "Unavailable");
  • To communicate the performed shifts of the last day of the previous planning period (i.e. last week);
 {
  "id": 1,
  "date": "2019-03-07",
  "employee": "E0",
  "skill": "Restaurant",
  "startDateTime": "2019-03-07T00:00:00",
  "endDateTime": "2019-03-07T21:00:00",
  "locked": true,
  "countAsWorkingHours": false,  
  "costs": { ... }
}
PropertyValueDescriptionRequired for Input
idIntegerA unique identifier for the assignmentRequired
dateLocalDateThe date of the assignment.Required
employeeStringThe name of the assigned employeeRequired
skillStringThe skill/workstation this employee is assigned toRequired
startIntegerThe starting shiftblockRequired
durationIntegerThe duration, expressed in shiftblocksRequired
startDateTimeLocalDateTimeThe starting hour for the assignmentOptional
endDateTimeLocalDateTimeThe end hour for the assignmentOptional
lockedBooleanIf this assignment is locked for the optimization or not.Optional
countAsWorkingHoursBooleanIf this assignment should be included in working hours per week/ month etc. constraints.Optional
costsCostsThe cost object associated with this assignment (see under)Optional

Solution

{
  "E0": [
    {
      "date": "2018-11-14",
      "index": 4
    },
    {
      "date": "2018-10-14",
      "index": 5
    },
    {
      "date": "2018-10-14",
      "index": 6
    }
  ],   
  "E1": [
    {
      "date": "2018-11-14",
      "index": 8
    }
  ]
}

When the problem is solved, the solution object returns the assigned Timeblocks per employee.
The assignments can also be found in the ShiftAssignments object. The assignment submitted in the solve request (if any) will be added to the ones constructed to solve the problem.
Once solved, The following objects can also be retrieved from the Employees object:

  • Hours
  • Costs

In addition, an aggregate Costs object can also be retrieved from the json, combining the costs of all employees.

Hours

{
  "hours": 12,
  "nightTimeHours": 2.5,
  "overTime1Hours": 0,
  "overTime2Hours": 0,
  "weeklyOverTimeHours": 0
}
PropertyValueDescription
hoursDoubleThe total number of hours assigned to this employee this planning period
nightTimeHoursDoubleThe number of hours, after the night threshold, assigned to this employee this planning period
overTime1HoursDoubleThe number of hours, after the first daily overtime threshold, assigned to this employee this planning period
overTime2HoursDoubleThe number of hours, after the second daily overtime threshold, assigned to this employee this planning period
weeklyOverTimeHoursDoubleThe number of hours, after the weekly overtime threshold, assigned to this employee this planning period

Costs

{
  "hourCost": 132,
  "nightTimeCost": 13.75,
  "overTime1Cost": 0,
  "overTime2Cost": 0,
  "weeklyOverTimeCost": 0
}
PropertyValueDescription
hourCostDoubleThe hour cost for this employee this planning period (excl. overtime, nightime, ...)
nightTimeCostDoubleThe cost associated with the hours, after the night threshold, for this employee this planning period
overTime1CostDoubleThe cost associated with the hours, after the first daily overtime threshold, for this employee this this planning period
overTime2CostDoubleThe cost associated with the hours, after the second daily overtime threshold, for this employee this this planning period
weeklyOverTimeCostDoubleThe cost associated with the hours, after the weekly overtime threshold, for this employee this this planning period

options

{
  "shiftBlocksPerDay": 24,
  "includeShiftPreferences:": false  
}

The definition of the options.

PropertyValueDescriptionRequired
shiftBlocksPerDayIntegerThe number of blocks in a dayRequired
includeShiftPreferencesBooleanWhether the shift preferences should be accommodated maximallyoptional
startDateDateA reference date for this planning periodoptional

What’s Next

Do you want to split up the phases "Shift Creation" and "Shift Filling", check out these solvers: