Overlapping shifts
There are situations where employees need to be assigned to multiple shifts that occur at the same time, for instance, their regular shift and an on call shift that overlaps their regular shift.
Prerequisites
Learn how to configure an API Key to run the examples in this guide:
-
Log in to Timefold Platform: app.timefold.ai
-
From the Dashboard, click your tenant, and from the drop-down menu select Tenant Settings, then choose API Keys.
-
Create a new API key or use an existing one. Ensure the list of models for the API key contains the Employee Shift Scheduling model.
In the examples, replace <API_KEY>
with the API Key you just copied.
1. Defining overlapping shift rules
Overlapping shifts rules are defined in contracts
.
{
"contracts": [
{
"id": "fullTimeContract",
"allowOverlappingShiftsRules": [
{
"id": "allowOverlapWithOnCallShift",
"includeShiftTags": [
"On call"
],
"shiftTagMatches": "ALL"
}
]
}
]
}
An allowOverlappingShiftsRules
must include an id
.
The Overlapping shifts
hard constraint makes sure only shifts with tags defined by the rule’s includeShiftTags
can overlap with other shifts.
Alternatively, only shifts without tags defined by the rule’s excludeShiftTags
can overlap with other shifts.
Further information about including or excluding shifts with shift tags:
Shifts with specific tags can be included or excluded by the rule. Tags are defined in shifts:
{
"shifts": [
{
"id": "2027-02-01",
"start": "2027-02-01T09:00:00Z",
"end": "2027-02-01T17:00:00Z",
"tags": ["Part-time"]
}
]
}
Use includeShiftTags
to include shifts with specific tags or excludeShiftTags
to exclude shifts with specific tags.
shiftTagMatches
can be set to ALL
or ANY
.
The default behavior for shiftTagMatches
is ALL
, and if omitted, the default ALL
will be used.
The rule can define either includeShiftTags
or excludeShiftTags
, but not both.
{
"includeShiftTags": ["Part-time", "Weekend"],
"shiftTagMatches": "ALL"
}
With shiftTagMatches
set to ALL
, all tags defined by the rule’s includeShiftTags
attribute must be present in the shift. With shiftTagMatches
set to ANY
, at least one tag defined by the rule’s includeShiftTags
attribute must be present in the shift.
{
"excludeShiftTags": ["Part-time", "Weekend"],
"shiftTagMatches": "ALL"
}
With shiftTagMatches
set to ALL
, all tags defined by the rule’s excludeShiftTags
attribute cannot be present in the shift.
This is useful when you want to exclude things in combination with each other.
For instance, excluding the shift tags Part-time
and Weekend
with shiftTagMatches
set to All
, will exclude shifts that include the tags Part-time
and Weekend
from the rule.
Shifts tagged only Part-time
or only Weekend
will not be excluded.
With shiftTagMatches
set to ANY
, any of the tags defined by the rule’s excludeShiftTags
attribute cannot be present in the shift.
This is useful when you need to exclude tags regardless of their relationship to other tags.
For instance, excluding the shift tags Part-time
and Weekend
with shiftTagMatches
set to ANY
, will exclude any shift that includes the tags Part-time
or Weekend
, whether they occur together or not.
2. Overlapping shift rules example
In the following example, Carl is assigned to a 24 hour on call shift that overlaps with his regular 8 hour shift.
-
Input
-
Output
Try this example in Timefold Platform by saving this JSON into a file called sample.json and make the following API call:
|
curl -X POST -H "Content-type: application/json" -H 'X-API-KEY: <API_KEY>' https://app.timefold.ai/api/models/employee-scheduling/v1/schedules [email protected]
{
"config": {
"run": {
"name": "Overlapping shifts rules example"
}
},
"modelInput": {
"contracts": [
{
"id": "fullTimeContract",
"allowOverlappingShiftsRules": [
{
"id": "allowOverlapWithOnCallShift",
"includeShiftTags": [
"On call"
],
"shiftTagMatches": "ALL"
}
]
}
],
"employees": [
{
"id": "Carl",
"contracts": [
"fullTimeContract"
]
}
],
"shifts": [
{
"id": "Mon on-call",
"start": "2027-02-01T00:00:00Z",
"end": "2027-02-02T00:00:00Z",
"tags": ["On call"]
},
{
"id": "Mon regular shift",
"start": "2027-02-01T09:00:00Z",
"end": "2027-02-01T17:00:00Z"
}
]
}
}
To request the solution, locate the 'ID' from the response to the post operation and append it to the following API call: |
curl -X GET -H 'X-API-KEY: <API_KEY>' https://app.timefold.ai/api/models/employee-scheduling/v1/schedules/<ID>
{
"run": {
"id": "ID",
"name": "Overlapping shifts rules example",
"submitDateTime": "2025-03-21T04:48:22.193823297Z",
"startDateTime": "2025-03-21T04:48:33.625081572Z",
"activeDateTime": "2025-03-21T04:48:33.773882421Z",
"completeDateTime": "2025-03-21T04:53:34.494085854Z",
"shutdownDateTime": "2025-03-21T04:53:34.766113937Z",
"solverStatus": "SOLVING_COMPLETED",
"score": "0hard/0medium/0soft",
"tags": [
"system.profile:default"
],
"validationResult": {
"summary": "OK"
}
},
"modelOutput": {
"shifts": [
{
"id": "Mon on-call",
"employee": "Carl"
},
{
"id": "Mon regular shift",
"employee": "Carl"
}
]
},
"inputMetrics": {
"employees": 1,
"shifts": 2,
"pinnedShifts": 0
},
"kpis": {
"assignedShifts": 2,
"unassignedShifts": 0,
"workingTimeFairnessPercentage": null,
"disruptionPercentage": 0.0,
"averageDurationOfEmployeesPreferencesMet": null,
"minimumDurationOfPreferencesMetAcrossEmployees": null,
"averageDurationOfEmployeesUnpreferencesViolated": null,
"maximumDurationOfUnpreferencesViolatedAcrossEmployees": null,
"activatedEmployees": 1,
"assignedMandatoryShifts": 2,
"assignedOptionalShifts": 0,
"travelDistance": 0
}
}
modelOutput
contains the schedule with overlapping shifts assigned to Carl.
inputMetrics
provides a breakdown of the inputs in the input dataset.
KPIs
provides the KPIs for the output including:
{
"assignedShifts": 2,
"unassignedShifts": 0
}
Next
-
See the full API spec or try the online API.
-
Learn more about employee shift scheduling from our YouTube playlist.
-
See other options for Shift rotations and patterns.