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.
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.
The rule can define either includeShiftTags
or excludeShiftTags
, not both.
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 run score when employees are assigned shifts that match the pattern.
Timefold is incentivized to use solutions with the best score.
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>
{
"run": {
"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.
{
"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 run score when an employee is assigned shifts in a pattern that is UNPREFERRED, incentivizing Timefold to find an alternative solution.
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>
{
"run": {
"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>
{
"run": {
"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.