Single day shift sequence patterns
Some employees work multiple shifts in a single day.
Single day shift patterns set rules about which combinations of shifts are preferred and which ones should be avoided or are prohibited altogether.
For instance, it might be preferable to have employees work shifts that occur close together to limit the number of times they need to commute to work in a single day.
Assigning shifts that occur in the afternoon and evening to the same employee can avoid causing unnecessary disruption to the employee’s day.
Assigning shifts that are several hours apart might not be ideal, but acceptable if there are no other alternatives.
Whereas assigning shifts at opposite ends of the day and impacting the employee’s ability to rest between shifts could be prohibited.
For options to minimize the gap between split shifts without single day shift sequence patterns, see Minimize gaps between shifts.
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. Define single day shift sequence patterns
Single day shift sequence patterns rules are configured in contracts:
{
"contracts": [
{
"id": "splitShiftContract",
"singleDayShiftSequencePatternRules": [
{
"id": "earlyShiftFollowedByMorningShift",
"pattern": [
{
"includeShiftTags": ["Early"],
"shiftTagMatches": "ALL"
},
{
"includeShiftTags": ["Morning"],
"shiftTagMatches": "ALL"
}
],
"satisfiability": "PREFERRED",
"ordered": true,
"weight": 10
}
]
}
]
}
singleDayShiftSequencePatternRules must include an ID.
pattern specifies the shifts that are included or excluded in the pattern based on the shift’s tags.
Use includeShiftTags to include shifts with specific tags or excludeShiftTags to exclude shifts with specific tags.
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.
ordered can be set to true or false.
True enforces the shifts being scheduled in the order they appear in the pattern.
weight can be used to make the pattern more important than other patterns.
For example, setting the weight to 2 will make the reward/penalty of this pattern’s elements count twice when matched.
Each employee must specify which contracts apply to them:
{
"employees": [
{
"id": "Ann",
"contracts": [
"partTimeContract"
]
}
]
}
Shifts must include tags:
{
"id": "Mon 0300",
"start": "2027-02-01T03:00:00Z",
"end": "2027-02-01T07:00:00Z",
"tags": ["Early"]
}
The satisfiability of the pattern can be PREFERRED, PROHIBITED, or UNPREFERRED.
2. Preferred single day shift sequence patterns
When the satisfiability of the rule is PREFERRED, the Employee works preferred single day shift sequence pattern soft constraint is invoked, which adds a soft reward to the dataset score when employees are assigned shifts that match the pattern.
Timefold is incentivized to use solutions with the best score.
|
By default, every constraint has a weight of Learn about changing the weight of this constraint:Use the constraint configuration’s
|
| This rule is more likely to be satisfied for employees with a higher employee priority. |
In the following example, there are two singleDayShiftSequencePatternRules:
-
Shifts tagged "Early" and "Morning" are preferably assigned together.
-
Shifts tagged "Afternoon" and "Late" are preferably assigned together.
Ann is assigned shifts tagged "Early" and "Morning", and Beth is assigned shifts tagged "Afternoon" and "Late".
-
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 single day shift pattern example"
}
},
"modelInput": {
"contracts": [
{
"id": "splitShiftContract",
"singleDayShiftSequencePatternRules": [
{
"id": "earlyShiftFollowedByMorningShift",
"pattern": [
{
"includeShiftTags": ["Early"],
"shiftTagMatches": "ALL"
},
{
"includeShiftTags": ["Morning"],
"shiftTagMatches": "ALL"
}
],
"satisfiability": "PREFERRED",
"ordered": true,
"weight": 10
},
{
"id": "afternoonShiftFollowedByLateShift",
"pattern": [
{
"includeShiftTags": ["Afternoon"],
"shiftTagMatches": "ALL"
},
{
"includeShiftTags": ["Late"],
"shiftTagMatches": "ALL"
}
],
"satisfiability": "PREFERRED",
"ordered": true,
"weight": 10
}
]
}
],
"employees": [
{
"id": "Ann",
"contracts": [
"splitShiftContract"
]
},
{
"id": "Beth",
"contracts": [
"splitShiftContract"
]
}
],
"shifts": [
{
"id": "Mon 03",
"start": "2027-02-01T03:00:00Z",
"end": "2027-02-01T07:00:00Z",
"tags": ["Early"]
},
{
"id": "Mon 08",
"start": "2027-02-01T08:00:00Z",
"end": "2027-02-01T12:00:00Z",
"tags": ["Morning"]
},
{
"id": "Mon 12",
"start": "2027-02-01T12:00:00Z",
"end": "2027-02-01T16:00:00Z",
"tags": ["Afternoon"]
},
{
"id": "Mon 17",
"start": "2027-02-01T17:00:00Z",
"end": "2027-02-01T21:00:00Z",
"tags": ["Late"]
}
]
}
}
| 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": "Preferred single day shift pattern example",
"submitDateTime": "2025-04-14T04:00:01.1887304Z",
"startDateTime": "2025-04-14T04:00:14.959991668Z",
"activeDateTime": "2025-04-14T04:00:15.195627078Z",
"completeDateTime": "2025-04-14T04:00:46.012389803Z",
"shutdownDateTime": "2025-04-14T04:00:46.308551364Z",
"solverStatus": "SOLVING_COMPLETED",
"score": "0hard/0medium/3840000soft",
"tags": [
"system.profile:default"
],
"validationResult": {
"summary": "OK"
}
},
"modelOutput": {
"shifts": [
{
"id": "Mon 03",
"employee": "Ann"
},
{
"id": "Mon 08",
"employee": "Ann"
},
{
"id": "Mon 12",
"employee": "Beth"
},
{
"id": "Mon 17",
"employee": "Beth"
}
]
},
"inputMetrics": {
"employees": 2,
"shifts": 4,
"pinnedShifts": 0
},
"kpis": {
"assignedShifts": 4,
"unassignedShifts": 0,
"assignedShiftGroups": 0,
"unassignedShiftGroups": 0,
"workingTimeFairnessPercentage": null,
"disruptionPercentage": 0.0,
"averageDurationOfEmployeesPreferencesMet": null,
"minimumDurationOfPreferencesMetAcrossEmployees": null,
"averageDurationOfEmployeesUnpreferencesViolated": null,
"maximumDurationOfUnpreferencesViolatedAcrossEmployees": null,
"activatedEmployees": 2,
"assignedMandatoryShifts": 4,
"assignedOptionalShifts": 0,
"travelDistance": 0
}
}
modelOutput contains the schedule with Ann assigned shifts tagged "Early" and "Morning" and Beth assigned shifts tagged "Afternoon" and "Late".
inputMetrics provides a breakdown of the inputs in the input dataset.
KPIs provides the KPIs for the output including:
{
"assignedShifts": 4,
"activatedEmployees": 2,
"assignedMandatoryShifts": 4
}
3. Unpreferred single day shift sequence patterns
When the satisfiability of the rule is UNPREFERRED, the Employee works unpreferred single day shift sequence pattern soft constraint is invoked.
|
By default, every constraint has a weight of Learn about changing the weight of this constraint:Use the constraint configuration’s
|
{
"contracts": [
{
"id": "splitShiftContract",
"singleDayShiftSequencePatternRules": [
{
"id": "earlyShiftFollowedByMorningShift",
"pattern": [
{
"includeShiftTags": ["Early"],
"shiftTagMatches": "ALL"
},
{
"includeShiftTags": ["Afternoon"],
"shiftTagMatches": "ALL"
}
],
"satisfiability": "UNPREFERRED",
"ordered": true,
"weight": 10
}
]
}
]
}
This constraint adds a soft penalty to the dataset score when an employee is assigned shifts in a pattern that is UNPREFERRED, incentivizing Timefold to find an alternative solution.
| This rule is more likely to be satisfied for employees with a higher employee priority. |
In the following example, there is one singleDayShiftSequencePatternRules:
-
Shifts tagged with "Early" and "Afternoon" are preferrably not assigned to individual employees.
There are only 2 shifts, and 1 employee. Ann is assigned shifts tagged "Early" and "Afternoon" and the solution is penalized with a negative soft 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": "Unpreferred single day shift pattern example"
}
},
"modelInput": {
"contracts": [
{
"id": "splitShiftContract",
"periodRules": [
{
"id": "Max8HoursPerDay",
"period": "DAY",
"satisfiability": "REQUIRED",
"minutesWorkedMax": 480
}
],
"singleDayShiftSequencePatternRules": [
{
"id": "earlyShiftFollowedByMorningShift",
"pattern": [
{
"includeShiftTags": ["Early"],
"shiftTagMatches": "ALL"
},
{
"includeShiftTags": ["Afternoon"],
"shiftTagMatches": "ALL"
}
],
"satisfiability": "UNPREFERRED",
"ordered": true,
"weight": 10
}
]
}
],
"employees": [
{
"id": "Ann",
"contracts": [
"splitShiftContract"
]
}
],
"shifts": [
{
"id": "Mon 03",
"start": "2027-02-01T03:00:00Z",
"end": "2027-02-01T07:00:00Z",
"tags": ["Early"]
},
{
"id": "Mon 12",
"start": "2027-02-01T12:00:00Z",
"end": "2027-02-01T16:00:00Z",
"tags": ["Afternoon"]
}
]
}
}
| 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": "Unpreferred single day shift pattern example",
"submitDateTime": "2025-04-14T05:00:32.456746712Z",
"startDateTime": "2025-04-14T05:00:43.557705033Z",
"activeDateTime": "2025-04-14T05:00:43.713611242Z",
"completeDateTime": "2025-04-14T05:01:14.53407709Z",
"shutdownDateTime": "2025-04-14T05:01:14.79050782Z",
"solverStatus": "SOLVING_COMPLETED",
"score": "0hard/0medium/-1920000soft",
"tags": [
"system.profile:default"
],
"validationResult": {
"summary": "OK"
}
},
"modelOutput": {
"shifts": [
{
"id": "Mon 03",
"employee": "Ann"
},
{
"id": "Mon 12",
"employee": "Ann"
}
]
},
"inputMetrics": {
"employees": 1,
"shifts": 2,
"pinnedShifts": 0
},
"kpis": {
"assignedShifts": 2,
"unassignedShifts": 0,
"assignedShiftGroups": 0,
"unassignedShiftGroups": 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 Ann assigned to both shifts.
inputMetrics provides a breakdown of the inputs in the input dataset.
KPIs provides the KPIs for the output including:
{
"assignedShifts": 2,
"activatedEmployees": 1,
"assignedMandatoryShifts": 2
}
4. Prohibited single day shift sequence patterns
When the satisfiability of the rule is PROHIBITED, the Employee works prohibited single day shift sequence pattern hard constraint is invoked.
{
"contracts": [
{
"id": "splitShiftContract",
"singleDayShiftSequencePatternRules": [
{
"id": "earlyShiftFollowedByMorningShift",
"pattern": [
{
"includeShiftTags": ["Early"],
"shiftTagMatches": "ALL"
},
{
"includeShiftTags": ["Late"],
"shiftTagMatches": "ALL"
}
],
"satisfiability": "PROHIBITED",
"ordered": true,
"weight": 10
}
]
}
]
}
Shifts will be left unassigned if assigning them would break the Employee works prohibited single day shift sequence pattern constraint.
In the following example, there is one singleDayShiftSequencePatternRules:
-
Shifts tagged "Early" and "Late" are prohibited from being assigned together to individual employees.
Ann is assigned the shift tagged "Early", but the shift tagged "Late" is left unassigned to avoid breaking the hard constraint.
-
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": "Prohibited single day shift pattern example"
}
},
"modelInput": {
"contracts": [
{
"id": "splitShiftContract",
"singleDayShiftSequencePatternRules": [
{
"id": "earlyShiftFollowedByMorningShift",
"pattern": [
{
"includeShiftTags": ["Early"],
"shiftTagMatches": "ALL"
},
{
"includeShiftTags": ["Late"],
"shiftTagMatches": "ALL"
}
],
"satisfiability": "PROHIBITED",
"ordered": true,
"weight": 10
}
]
}
],
"employees": [
{
"id": "Ann",
"contracts": [
"splitShiftContract"
]
}
],
"shifts": [
{
"id": "Mon 03",
"start": "2027-02-01T03:00:00Z",
"end": "2027-02-01T07:00:00Z",
"tags": ["Early"]
},
{
"id": "Mon 17",
"start": "2027-02-01T17:00:00Z",
"end": "2027-02-01T21:00:00Z",
"tags": ["Late"]
}
]
}
}
| 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": "Prohibited single day shift pattern example",
"submitDateTime": "2025-04-14T05:06:47.106470925Z",
"startDateTime": "2025-04-14T05:07:02.386223943Z",
"activeDateTime": "2025-04-14T05:07:02.610949643Z",
"completeDateTime": "2025-04-14T05:07:33.472871088Z",
"shutdownDateTime": "2025-04-14T05:07:33.659151333Z",
"solverStatus": "SOLVING_COMPLETED",
"score": "0hard/-1medium/0soft",
"tags": [
"system.profile:default"
],
"validationResult": {
"summary": "OK"
}
},
"modelOutput": {
"shifts": [
{
"id": "Mon 03",
"employee": "Ann"
},
{
"id": "Mon 17",
"employee": null
}
]
},
"inputMetrics": {
"employees": 1,
"shifts": 2,
"pinnedShifts": 0
},
"kpis": {
"assignedShifts": 1,
"unassignedShifts": 1,
"assignedShiftGroups": 0,
"unassignedShiftGroups": 0,
"workingTimeFairnessPercentage": null,
"disruptionPercentage": 0.0,
"averageDurationOfEmployeesPreferencesMet": null,
"minimumDurationOfPreferencesMetAcrossEmployees": null,
"averageDurationOfEmployeesUnpreferencesViolated": null,
"maximumDurationOfUnpreferencesViolatedAcrossEmployees": null,
"activatedEmployees": 1,
"assignedMandatoryShifts": 1,
"assignedOptionalShifts": 0,
"travelDistance": 0
}
}
modelOutput contains the schedule with Ann assigned to only one shift.
inputMetrics provides a breakdown of the inputs in the input dataset.
KPIs provides the KPIs for the output including:
{
"assignedShifts": 1,
"unassignedShifts": 1,
"activatedEmployees": 1,
"assignedMandatoryShifts": 1
}
Next
-
See the full API spec or try the online API.
-
Learn more about employee shift scheduling from our YouTube playlist.
-
Working with Employee availability.