Consecutive days worked
There are different techniques for managing employees' working hours.
For different scenarios see Work limits.
This guide shows you how to manage employees' hours with consecutive days worked per period, for instance, to limit the maximum number of consecutive days employees can be assigned shifts to work.
1. Define consecutive days worked rules
Learn how to configure an API Key to run the examples in this guide:
In the examples, replace |
Consecutive day worked rules are defined in contracts.
{
"contracts": [
{
"id": "fullTimeContract",
"consecutiveDaysWorkedRules": [
{
"id": "Max3Consecutive12HourShifts",
"maximum": 3,
"satisfiability": "REQUIRED"
}
]
}
]
}
A consecutiveDaysWorkedRules must include an ID.
maximum defines the maximum number of shifts on consecutive days an employee with this contract can work.
consecutiveDaysWorkedRules can include or exclude shifts based on shift tags.
{
"consecutiveDaysWorkedRules": [
{
"id": "Max3Consecutive12HourShifts",
"maximum": 3,
"satisfiability": "REQUIRED",
"includeShiftTags": ["Part-time"],
"shiftTagMatches": "ALL"
}
]
}
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.
shiftTypesTagCategories can be used to limit consecutive days worked on shifts with specific tags, for instance, shifts tagged with Day or Night.
{
"consecutiveDaysWorkedRules": [
{
"id": "Max3Consecutive12HourShifts",
"maximum": 3,
"satisfiability": "REQUIRED",
"shiftTypesTagCategories": [
"Day", "Night"
]
}
]
}
With the maximum set to 3 and shiftTypesTagCategories including the tags Day and Night, employees will not be assigned more than 3 consecutive day shifts or 3 consecutive night shifts.
However, they could be assigned 3 consecutive day shifts followed by 3 consecutive night shifts, or vice versa.
Shifts can have the tag Day or Night but not both.
The satisfiability of the rule can be REQUIRED or PREFERRED.
If omitted, REQUIRED is the default.
1.1. Counting days in consecutive days worked rules
By default, the rule counts a day as worked if a shift starts on that day. For instance, if an employee works 3 back-to-back shifts and the last shift of the sequence starts on the previous day but ends the following morning, it will only be counted towards the previous day.
To change this behavior, set the field overlapKind from START_ONLY to START_AND_END.
{
"consecutiveDaysWorkedRules": [
{
"id": "Max3ConsecutiveDaysWorked",
"maximum": 3,
"satisfiability": "REQUIRED",
"overlapKind": "START_AND_END"
}
]
}
2. Required consecutive days worked
When the satisfiability of the rule is REQUIRED, the Consecutive days worked not in required range for employee hard constraint is invoked, which makes sure the number of shifts on consecutive days does not exceed the limit specified in maximum.
| The day is considered worked if the employee is assigned to at least one shift that starts on that day. Shifts that start on the previous day and end on the current day are not considered. |
Shifts will be left unassigned if assigning them would break the Consecutive days worked not in required range for employee constraint.
In the following example, there are 4 shifts and 1 employee. Beth has a contract that allows her to work shifts on a maximum of 3 consecutive days.
Beth is assigned 3 consecutive shifts and 1 shift is left unassigned.
-
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": "Required consecutive days worked example"
}
},
"modelInput": {
"contracts": [
{
"id": "fullTimeContract",
"consecutiveDaysWorkedRules": [
{
"id": "Max3Consecutive12HourShifts",
"maximum": 3,
"satisfiability": "REQUIRED"
}
]
}
],
"employees": [
{
"id": "Beth",
"contracts": [
"fullTimeContract"
]
}
],
"shifts": [
{
"id": "Mon",
"start": "2027-02-01T08:00:00Z",
"end": "2027-02-01T20:00:00Z"
},
{
"id": "Tue",
"start": "2027-02-02T08:00:00Z",
"end": "2027-02-02T20:00:00Z"
},
{
"id": "Wed",
"start": "2027-02-03T08:00:00Z",
"end": "2027-02-03T20:00:00Z"
},
{
"id": "Thu",
"start": "2027-02-04T08:00:00Z",
"end": "2027-02-04T20: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>
{
"metadata": {
"id": "ID",
"name": "Required consecutive days worked example",
"submitDateTime": "2025-03-18T06:39:19.37242389Z",
"startDateTime": "2025-03-18T06:39:30.34936678Z",
"activeDateTime": "2025-03-18T06:39:30.58964911Z",
"completeDateTime": "2025-03-18T06:44:31.318789334Z",
"shutdownDateTime": "2025-03-18T06:44:31.541517086Z",
"solverStatus": "SOLVING_COMPLETED",
"score": "0hard/-1medium/0soft",
"tags": [
"system.profile:default"
],
"validationResult": {
"summary": "OK"
}
},
"modelOutput": {
"shifts": [
{
"id": "Mon",
"employee": "Beth"
},
{
"id": "Tue",
"employee": "Beth"
},
{
"id": "Wed",
"employee": "Beth"
},
{
"id": "Thu",
"employee": null
}
]
},
"inputMetrics": {
"employees": 1,
"shifts": 4,
"pinnedShifts": 0
},
"kpis": {
"assignedShifts": 3,
"unassignedShifts": 1,
"workingTimeFairnessPercentage": null,
"disruptionPercentage": 0.0,
"averageDurationOfEmployeesPreferencesMet": null,
"minimumDurationOfPreferencesMetAcrossEmployees": null,
"averageDurationOfEmployeesUnpreferencesViolated": null,
"maximumDurationOfUnpreferencesViolatedAcrossEmployees": null,
"activatedEmployees": 1,
"assignedMandatoryShifts": 3,
"assignedOptionalShifts": 0,
"travelDistance": 0
}
}
3. Preferred consecutive days worked
When the satisfiability of the rule is PREFERRED, the Consecutive days worked not in preferred range for employee soft constraint is invoked.
With a satisfiability of PREFERRED a minimum value can also be provided to set the minimum number of consecutive days an employee can be assigned shifts.
REQUIRED satisfiability is not supported with `minimum'.
|
{
"contracts": [
{
"id": "fullTimeContract",
"consecutiveDaysWorkedRules": [
{
"id": "Min2Max3ConsecutiveShifts",
"maximum": 3,
"minimum": 2,
"satisfiability": "PREFERRED"
}
]
}
]
}
If there is no alternative, shifts will still be assigned to employees even if assigning the shifts breaks the Consecutive days worked not in preferred range for employee soft constraint.
This constraint adds a soft penalty to the dataset score for any matches to the constraint, incentivizing Timefold to find an alternative solution.
|
Every soft constraint has a weight that can be configured to change the relative importance of the constraint compared to other constraints. Learn about constraint weights. |
| This rule is more likely to be satisfied for employees with a higher employee priority. |
In the following example, there are 4 shifts and 1 employee. Beth has a contract that allows her to work shifts on a preferred maximum of 3 consecutive days.
Beth is assigned all 4 consecutive shifts and a soft penalty is applied to the dataset score.
-
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": "Preferred consecutive days worked example"
}
},
"modelInput": {
"contracts": [
{
"id": "fullTimeContract",
"consecutiveDaysWorkedRules": [
{
"id": "Max3Consecutive12HourShifts",
"maximum": 3,
"satisfiability": "PREFERRED"
}
]
}
],
"employees": [
{
"id": "Beth",
"contracts": [
"fullTimeContract"
]
}
],
"shifts": [
{
"id": "Mon",
"start": "2027-02-01T08:00:00Z",
"end": "2027-02-01T20:00:00Z"
},
{
"id": "Tue",
"start": "2027-02-02T08:00:00Z",
"end": "2027-02-02T20:00:00Z"
},
{
"id": "Wed",
"start": "2027-02-03T08:00:00Z",
"end": "2027-02-03T20:00:00Z"
},
{
"id": "Thu",
"start": "2027-02-04T08:00:00Z",
"end": "2027-02-04T20: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>
{
"metadata": {
"id": "ID7",
"name": "Preferred consecutive days worked example",
"submitDateTime": "2025-05-23T08:29:39.286257221Z",
"startDateTime": "2025-05-23T08:29:56.095375304Z",
"activeDateTime": "2025-05-23T08:29:56.254538641Z",
"completeDateTime": "2025-05-23T08:30:26.999013804Z",
"shutdownDateTime": "2025-05-23T08:30:27.289197001Z",
"solverStatus": "SOLVING_COMPLETED",
"score": "0hard/0medium/-960soft",
"tags": [
"system.profile:default"
],
"validationResult": {
"summary": "OK"
}
},
"modelOutput": {
"shifts": [
{
"id": "Mon",
"employee": "Beth"
},
{
"id": "Tue",
"employee": "Beth"
},
{
"id": "Wed",
"employee": "Beth"
},
{
"id": "Thu",
"employee": "Beth"
}
]
},
"inputMetrics": {
"employees": 1,
"shifts": 4,
"pinnedShifts": 0
},
"kpis": {
"assignedShifts": 4,
"unassignedShifts": 0,
"disruptionPercentage": 0.0,
"activatedEmployees": 1,
"assignedMandatoryShifts": 4,
"assignedOptionalShifts": 0,
"travelDistance": 0
}
}
4. Managing overtime
Rules with a satisfiability of REQUIRED put a hard limit on how much work employees can be assigned (minutes, hours, days, shifts), and does not assign overtime.
A rule with a satisfiability of REQUIRED that states an employee can work a maximum of 4 consecutive days, will never assign the employee more than 4 consecutive days, even if assigning overtime would be beneficial to the overall schedule.
To allow for the possibility of overtime, use rules with a satisfiability of PREFERRED.
Set a rule with a PREFERRED satisfiability for the maximum number of consecutive days.
Now, a rule with a satisfiability of PREFERRED that states an employee can preferably work a maximum of 4 consecutive days will allow the employee to be assigned more consecutive days (overtime) than specified by the rule when it is necessary to do so.
To place a limit on the total amount of overtime employees can be assigned, include both:
-
A rule with
PREFERREDsatisfiability for the maximum number of consecutive days that is equivalent to the employees normal consecutive days. -
A rule with
REQUIREDsatisfiability for the maximum number of consecutive days (regular hours plus overtime).
The difference between the PREFERRED maximum consecutive days and REQUIRED maximum consecutive days is the total amount of overtime that can be assigned to employees.
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 managing employees' work hours: Work limits.
-
Learn about shift sequences with consecutive days worked: Consecutive days worked and shift sequences.