Docs
  • Solver
  • Models
    • Field Service Routing
    • Employee Shift Scheduling
  • Platform
Try models
  • Employee Shift Scheduling
  • Shift service constraints
  • Shift sequence patterns: multi-day shifts

Employee Shift Scheduling

    • Introduction
    • Planning AI concepts
    • Metrics and optimization goals
    • Getting started with employee shift scheduling
    • Understanding the API
    • Employee shift scheduling user guide
    • Employee resource constraints
      • Employee availability
      • Employee contracts
      • Employee contracts: period rules
      • Employee contracts: shift rules
      • Fairness
      • Pairing employees
      • Shift travel and locations
    • Shift service constraints
      • Alternative shifts
      • Demand and supply
      • Mandatory and optional visits
      • Shift assignments
      • Shift sequence patterns: single day shifts
      • Shift sequence patterns: multi-day shifts
      • Shift sequence patterns: daily shift pairings
      • Skills and risk factors
    • Recommendations
    • Real-time planning
    • Time zones and Daylight Saving Time (DST)
    • New and noteworthy
    • Upgrading to the latest versions
    • Feature requests

Shift sequence patterns: multi-day shifts

Employees often work across multiple days that must be scheduled in specific patterns.

Multi-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 preferrable to have employees work a specific number of shifts in a row, followed by a specific number of days off or employees might work a specific number of shifts types followed by a specific number of shifts of a different type.

This guide explains how to manage multi-day shift sequence patterns with the following examples:

  • Multi-day shift sequence

    • Preferred satisfiability

    • Unpreferred satisfiability

    • Prohibited satisfiability

Prerequisites

To run the examples in this guide, you need to authenticate with a valid API key for the Employee Shift Scheduling model:

  1. Log in to Timefold Platform: app.timefold.ai

  2. From the Dashboard, click your tenant, and from the drop-down menu select Tenant Settings, then choose API Keys.

  3. 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. Multi-day shift sequence

Multi-day shift sequence pattern rules are configured in contracts:

{
  "contracts": [
    {
      "id": "shiftContract",
      "multiDayShiftSequencePatternRules": [
        {
          "id": "2DaysOn2DaysOff",
          "pattern": [
            {
              "type": "ON",
              "includeShiftTags": [
                "Day"
              ],
              "shiftTagMatches": "ALL"
            },
            {
              "type": "ON",
              "includeShiftTags": [
                "Day"
              ],
              "shiftTagMatches": "ALL"
            },
            {
              "type": "OFF"
            },
            {
              "type": "OFF"
            }
          ],
          "satisfiability": "PREFERRED",
          "weight": 1
        }
      ]
    }
  ]
}

multiDayShiftSequencePatternRules must include an ID.

pattern specifies the shifts that are included or excluded in the pattern based on the shift’s tags and the order in which the shifts occur.

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, not both.

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.

shiftMatches is used when there are multiple shifts on a single day, you can configure the pattern to match ALL the shifts, or ANY of the shifts using the shiftMatches attribute.

{
  "pattern": [
    {
      "type": "ON",
      "includeShiftTags": [
        "Day"
      ],
      "shiftTagMatches": "ALL",
      "shiftMatches": "ANY"
    }
  ]
}

When a pattern starts or ends with OFF, you must specify the planning window interval to ensure the pattern matches properly throughout the period you are planning for.

{
  "planningWindow": {
    "start": "2027-02-01T00:00:00Z",
    "end": "2027-02-09T00:00:00Z"
  }
}

Each employee must specify which contracts apply to them:

{
  "employees": [
    {
      "id": "Ann",
      "contracts": [
        "partTimeContract"
      ]
    }
  ]
}

Multi-day patterns can be defined without using tags, however, if the pattern uses tags to match specific shift types, shifts must also include tags:

{
  "id": "Mon 0300",
  "start": "2027-02-01T03:00:00Z",
  "end": "2027-02-01T07:00:00Z",
  "tags": ["Early"]
}

satisfiability of the pattern can be PREFERRED, PROHIBITED, or UNPREFERRED.

1.1. Preferred satisfiability

When the satisfiability of the rule is PREFERRED, the Employee works preferred multi 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.

Shifts that do not match the pattern, will still be assigned if there is no alternative.

In the following example, there are 8 shifts and 2 employees. There is one multiDayShiftSequencePatternRules:

  1. Employees work 4 consecutive days on and 4 consecutive days off.

Ann is assigned the first 4 consecutive shifts and Beth is assigned the next 4 consecutive shifts.

multi day shift patterns preferred
  • 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": "Multi-day shift pattern rules - preferred"
    }
  },
  "modelInput": {
    "contracts": [
      {
        "id": "shiftContract",
        "multiDayShiftSequencePatternRules": [
          {
            "id": "4DaysOn4DaysOff",
            "pattern": [
              {
                "type": "ON",
                "includeShiftTags": [
                  "Day"
                ],
                "shiftTagMatches": "ALL"
              },
              {
                "type": "ON",
                "includeShiftTags": [
                  "Day"
                ],
                "shiftTagMatches": "ALL"
              },
              {
                "type": "ON",
                "includeShiftTags": [
                  "Day"
                ],
                "shiftTagMatches": "ALL"
              },
              {
                "type": "ON",
                "includeShiftTags": [
                  "Day"
                ],
                "shiftTagMatches": "ALL"
              },
              {
                "type": "OFF"
              },
              {
                "type": "OFF"
              },
              {
                "type": "OFF"
              },
              {
                "type": "OFF"
              }
            ],
            "satisfiability": "PREFERRED",
            "weight": 1
          }
        ]
      }
    ],
    "employees": [
      {
        "id": "Ann",
        "contracts": [
          "shiftContract"
        ]
      },
      {
        "id": "Beth",
        "contracts": [
          "shiftContract"
        ]
      }
    ],
    "shifts": [
      {
        "id": "Mon Day",
        "start": "2027-02-01T06:00:00Z",
        "end": "2027-02-01T18:00:00Z",
        "tags": ["Day"]
      },
      {
        "id": "Tue Day",
        "start": "2027-02-02T06:00:00Z",
        "end": "2027-02-02T18:00:00Z",
        "tags": ["Day"]
      },
      {
        "id": "Wed Day",
        "start": "2027-02-03T06:00:00Z",
        "end": "2027-02-03T18:00:00Z",
        "tags": ["Day"]
      },
      {
        "id": "Thu Day",
        "start": "2027-02-04T06:00:00Z",
        "end": "2027-02-04T18:00:00Z",
        "tags": ["Day"]
      },
      {
        "id": "Fri Day",
        "start": "2027-02-05T06:00:00Z",
        "end": "2027-02-05T18:00:00Z",
        "tags": ["Day"]
      },
      {
        "id": "Sat Day",
        "start": "2027-02-06T06:00:00Z",
        "end": "2027-02-06T18:00:00Z",
        "tags": ["Day"]
      },
      {
        "id": "Sun Day",
        "start": "2027-02-07T06:00:00Z",
        "end": "2027-02-07T18:00:00Z",
        "tags": ["Day"]
      },
      {
        "id": "Mon Day 2",
        "start": "2027-02-08T06:00:00Z",
        "end": "2027-02-08T18:00:00Z",
        "tags": ["Day"]
      }
    ],
    "planningWindow": {
      "start": "2027-02-01T00:00:00Z",
      "end": "2027-02-09T00: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": "Multi-day shift pattern rules - preferred",
    "submitDateTime": "2025-04-17T05:42:12.053757236Z",
    "startDateTime": "2025-04-17T05:42:28.93501674Z",
    "activeDateTime": "2025-04-17T05:42:29.057374899Z",
    "completeDateTime": "2025-04-17T05:42:59.881667907Z",
    "shutdownDateTime": "2025-04-17T05:43:00.075651383Z",
    "solverStatus": "SOLVING_COMPLETED",
    "score": "0hard/0medium/61440soft",
    "tags": [
      "system.profile:default"
    ],
    "validationResult": {
      "summary": "OK"
    }
  },
  "modelOutput": {
    "shifts": [
      {
        "id": "Mon Day",
        "employee": "Ann"
      },
      {
        "id": "Tue Day",
        "employee": "Ann"
      },
      {
        "id": "Wed Day",
        "employee": "Ann"
      },
      {
        "id": "Thu Day",
        "employee": "Ann"
      },
      {
        "id": "Fri Day",
        "employee": "Beth"
      },
      {
        "id": "Sat Day",
        "employee": "Beth"
      },
      {
        "id": "Sun Day",
        "employee": "Beth"
      },
      {
        "id": "Mon Day 2",
        "employee": "Beth"
      }
    ]
  },
  "inputMetrics": {
    "employees": 2,
    "shifts": 8,
    "pinnedShifts": 0
  },
  "kpis": {
    "assignedShifts": 8,
    "unassignedShifts": 0,
    "assignedShiftGroups": 0,
    "unassignedShiftGroups": 0,
    "workingTimeFairnessPercentage": null,
    "disruptionPercentage": 0.0,
    "averageDurationOfEmployeesPreferencesMet": null,
    "minimumDurationOfPreferencesMetAcrossEmployees": null,
    "averageDurationOfEmployeesUnpreferencesViolated": null,
    "maximumDurationOfUnpreferencesViolatedAcrossEmployees": null,
    "activatedEmployees": 2,
    "assignedMandatoryShifts": 8,
    "assignedOptionalShifts": 0,
    "travelDistance": 0
  }
}

modelOutput contains the schedule with Ann assigned to 4 shifts on then 4 days off, and Beth assigned to 4 days off then 4 shifts on.

inputMetrics provides a breakdown of the inputs in the input dataset.

KPIs provides the KPIs for the output including:

{
  "assignedShifts": 8,
  "activatedEmployees": 2,
  "assignedMandatoryShifts": 8
}

1.2. Unpreferred satisfiability

When the satisfiability of the rule is UNPREFERRED, the Employee works unpreferred multi day shift sequence pattern soft constraint is invoked.

{
  "contracts": [
    {
      "id": "shiftContract",
      "multiDayShiftSequencePatternRules": [
        {
          "id": "1DayOn1DayOff1DayOn1DayOff",
          "pattern": [
            {
              "type": "ON",
              "includeShiftTags": [
                "Day"
              ],
              "shiftTagMatches": "ALL"
            },
            {
              "type": "OFF"
            },
            {
              "type": "ON",
              "includeShiftTags": [
                "Day"
              ],
              "shiftTagMatches": "ALL"
            },
            {
              "type": "OFF"
            }
          ],
          "satisfiability": "UNPREFERRED",
          "weight": 1
        }
      ]
    }
  ]
}

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 multiDayShiftSequencePatternRules:

  • Employees should not work 1 day on, then 1 off, then 1 day on, then another day off.

There are only 2 shifts, and 1 employee. The shifts are on Monday and Wednesday. Assigning the shifts to Ann breaks the pattern and a soft penalty is applied to the run score.

multi day shift patterns unpreferred
  • 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": "Multi-day shift pattern rules - unpreferred"
    }
  },
  "modelInput": {
    "contracts": [
      {
        "id": "shiftContract",
        "multiDayShiftSequencePatternRules": [
          {
            "id": "1DayOn1DayOff1DayOn1DayOff",
            "pattern": [
              {
                "type": "ON",
                "includeShiftTags": [
                  "Day"
                ],
                "shiftTagMatches": "ALL"
              },
              {
                "type": "OFF"
              },
              {
                "type": "ON",
                "includeShiftTags": [
                  "Day"
                ],
                "shiftTagMatches": "ALL"
              },
              {
                "type": "OFF"
              }
            ],
            "satisfiability": "UNPREFERRED",
            "weight": 1
          }
        ]
      }
    ],
    "employees": [
      {
        "id": "Ann",
        "contracts": [
          "shiftContract"
        ]
      }
    ],
    "shifts": [
      {
        "id": "Mon Day",
        "start": "2027-02-01T06:00:00Z",
        "end": "2027-02-01T18:00:00Z",
        "tags": ["Day"]
      },
      {
        "id": "Wed Day",
        "start": "2027-02-03T06:00:00Z",
        "end": "2027-02-03T18:00:00Z",
        "tags": ["Day"]
      }
    ],
    "planningWindow": {
      "start": "2027-02-01T00:00:00Z",
      "end": "2027-02-05T00: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": "Multi-day shift pattern rules - unpreferred",
    "submitDateTime": "2025-04-17T07:04:27.137312142Z",
    "startDateTime": "2025-04-17T07:04:38.65529439Z",
    "activeDateTime": "2025-04-17T07:04:38.845195643Z",
    "completeDateTime": "2025-04-17T07:05:09.666946748Z",
    "shutdownDateTime": "2025-04-17T07:05:09.962379646Z",
    "solverStatus": "SOLVING_COMPLETED",
    "score": "0hard/0medium/-3840soft",
    "tags": [
      "system.profile:default"
    ],
    "validationResult": {
      "summary": "OK"
    }
  },
  "modelOutput": {
    "shifts": [
      {
        "id": "Mon Day",
        "employee": "Ann"
      },
      {
        "id": "Wed Day",
        "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 2 shifts that break the multi-day shift pattern.

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
}

1.3. Prohibited satisfiability

When the satisfiability of the rule is PROHIBITED, the Employee works prohibited multi day shift sequence pattern hard constraint is invoked.

{
  "contracts": [
    {
      "id": "shiftContract",
      "multiDayShiftSequencePatternRules": [
        {
          "id": "noLateFollowedByEarly",
          "pattern": [
            {
              "type": "ON",
              "includeShiftTags": [
                "Late"
              ],
              "shiftTagMatches": "ALL"
            },
            {
              "type": "ON",
              "includeShiftTags": [
                "Early"
              ],
              "shiftTagMatches": "ALL"
            }
          ],
          "satisfiability": "PROHIBITED",
          "weight": 1
        }
      ]
    }
  ]
}

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 1 late shift followed by 1 early shift the next day. There is only 1 employee.

There is 1 multiDayShiftSequencePatternRules:

  • Employees cannot work a "Late" shift followed by an "Early" shift the next day.

multi day shift patterns prohbited
  • 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": "Multi-day shift pattern rules - prohibited"
    }
  },
  "modelInput": {
    "contracts": [
      {
        "id": "shiftContract",
        "multiDayShiftSequencePatternRules": [
          {
            "id": "noLateFollowedByEarly",
            "pattern": [
              {
                "type": "ON",
                "includeShiftTags": [
                  "Late"
                ],
                "shiftTagMatches": "ALL"
              },
              {
                "type": "ON",
                "includeShiftTags": [
                  "Early"
                ],
                "shiftTagMatches": "ALL"
              }
            ],
            "satisfiability": "PROHIBITED",
            "weight": 1
          }
        ]
      }
    ],
    "employees": [
      {
        "id": "Ann",
        "contracts": [
          "shiftContract"
        ]
      }
    ],
    "shifts": [
      {
        "id": "Mon",
        "start": "2027-02-01T16:00:00Z",
        "end": "2027-02-02T00:00:00Z",
        "tags": ["Late"]
      },
      {
        "id": "Tue",
        "start": "2027-02-02T00:00:00Z",
        "end": "2027-02-02T08:00:00Z",
        "tags": ["Early"]
      }
    ]
  }
}
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": "Multi-day shift pattern rules - prohibited",
    "submitDateTime": "2025-04-17T08:40:50.397686975Z",
    "startDateTime": "2025-04-17T08:41:03.819058992Z",
    "activeDateTime": "2025-04-17T08:41:03.990649293Z",
    "completeDateTime": "2025-04-17T08:41:34.845305126Z",
    "shutdownDateTime": "2025-04-17T08:41:35.037087833Z",
    "solverStatus": "SOLVING_COMPLETED",
    "score": "0hard/-1medium/0soft",
    "tags": [
      "system.profile:default"
    ],
    "validationResult": {
      "summary": "OK"
    }
  },
  "modelOutput": {
    "shifts": [
      {
        "id": "Mon",
        "employee": "Ann"
      },
      {
        "id": "Tue",
        "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 scheduled a "Late" shift, but with the "Early" shift the next day left unassigned.

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
}

1.4. Mandatory and optional shifts with multi-day shift patterns

When it is preferable to assign shifts that match the multi-day shift pattern at the expense of leaving some shifts unassigned, custom priorities can be defined so that shifts are considered optional and will not be assigned if assigning them would break the multi-day pattern.

See mandatory and optional shifts for more information.

Next

  • See the Employee shift scheduling user guide

  • Understand the constraints of the Employee Shift Scheduling model.

  • See the full API spec or try the online API.

  • Manage schedules with Time zones and Daylight Saving Time (DST) changes.

  • Working with Employee availability.

  • © 2025 Timefold BV
  • Timefold.ai
  • Documentation
  • Changelog
  • Send feedback
  • Privacy
  • Legal
    • Light mode
    • Dark mode
    • System default