Docs
  • Solver
  • Models
    • Field Service Routing
    • Employee Shift Scheduling
    • Pick-up and Delivery Routing
  • Platform
Try models
  • Employee Shift Scheduling
  • Employee resource constraints
  • Time off
  • Consecutive minutes off in a rolling window
  • latest
    • latest
    • 1.20.x

Employee Shift Scheduling

    • Introduction
    • Getting started: Hello world
    • User guide
      • Terms
      • Use case guide
      • Planning AI concepts
      • Integration
      • Constraints
      • Understanding the API
      • Demo datasets
      • Input datasets
        • Model configuration
        • Model input
        • Planning window
      • Planning window
      • Time zones and Daylight Saving Time (DST)
      • Tags and tag types
      • Input validation
      • Metrics and optimization goals
      • Score analysis
      • Visualizations
    • Employee resource constraints
      • Employee contracts
      • Employee availability
      • Employee priority
      • Pairing employees
      • Shift travel and locations
      • Employee activation
      • Work limits
        • Minutes worked per period
        • Minutes worked in a rolling window
        • Minutes logged per period
        • Days worked per period
        • Days worked in a rolling window
        • Consecutive days worked
        • Shifts worked per period
        • Shifts worked in a rolling window
        • Weekend minutes worked per period
        • Weekends worked per period
        • Weekends worked in a rolling window
        • Consecutive weekends worked
      • Time off
        • Days off per period
        • Consecutive days off per period
        • Consecutive days off in a rolling window
        • Consecutive minutes off in a rolling window
        • Shifts to avoid close to day off requests
        • Consecutive weekends off per period
      • Shift rotations and patterns
        • Shift rotations
        • Single day shift sequence patterns
        • Minimize gaps between shifts
        • Multi-day shift sequence patterns
        • Daily shift pairings
        • Overlapping shifts
        • Shift start times differences
        • Minutes between shifts
      • Shift type diversity
        • Shift tag types
        • Shift types worked per period
        • Unique tags per period
      • Fairness
        • Balance time worked
        • Balance shift count
    • Shift service constraints
      • Alternative shifts
      • Cost management
      • Demand-based scheduling
      • Mandatory and optional shifts
      • Shift assignments
      • Skills and risk factors
    • Manual intervention
    • Recommendations
    • Real-time planning
    • Real-time planning (preview)
    • Scenarios
      • Configuring labor law compliance
      • Configuring employee well-being
    • Changelog
    • Upgrade to the latest version
    • Feature requests

Consecutive minutes off in a rolling window

There are different techniques for managing employee’s time off.

Consecutive minutes off in a rolling window is useful for employees who don’t work conventional Monday to Friday, 9am to 5pm, shifts. For instance, if an employee can work any 5 days in a 7-day period with 2880 consecutive minutes (2 days) off.

This guide explains managing consecutive minutes off in a rolling window:

  • 1. Define consecutive minutes off in a rolling window rules
  • 2. Required consecutive minutes off in rolling windows
  • 3. Preferred consecutive minutes off in rolling windows
  • 4. Consecutive minutes off interval in a rolling window
  • 5. Consecutive minutes off conditionally in a rolling window

1. Define consecutive minutes off in a rolling window rules

Learn how to configure an API Key to run the examples in this guide:
  1. Log in to Timefold Platform: app.timefold.ai

  2. From the Dashboard, click your tenant, and from the drop-down menu select Manage tenant, 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.

Rolling window rules are defined in contracts:

{
  "contracts": [
    {
      "id": "fullTimeContract",
      "rollingWindowRules": [
        {
          "id": "2880ConsecutiveMinutesOffRollingWindow",
          "rollingWindow": {
            "type": "DAILY",
            "size": 7
          },
          "consecutiveMinutesOffLimit":
          {
            "consecutiveMinutesOffMin": 2880
          },
          "satisfiability": "REQUIRED"
        }
      ]
    }
  ]
}

You can define as many rollingWindowRules as required.

rollingWindowRules must include an ID.

rollingWindow specifies the type and size of the window.

Further information about rollingWindows:

size sets how many instances of type are included in the rolling window, for instance, the following example specifies a rolling window of 7 days.

{
  "rollingWindow": {
    "type": "DAILY",
    "size": 7
  }
}

There are three types of rolling windows HOURLY, DAILY, and WEEKLY.

The type specifies how the rolling window progress, hour-by-hour, day-by-day, or week-by-week.

  • HOURLY spans the number of hours specified in size and occurs every hour when shifts are scheduled. The hourly window starts when a shift starts (for example 8:00, or 14:30)

  • DAILY spans the number of days specified in size for 24-hour periods and covers the entire schedule. The daily window starts at the beginning of a calendar day (midnight).

  • WEEKLY spans the number of weeks specified in size and occurs every week (including partial weeks) in the schedule. The weekly window starts at the beginning of a calendar week (usually Monday, or Sunday).

By default, the start of the week is Monday, however, this can be overridden for the entire schedule:

{
  "scheduleParameterization": {
    "weekStart": "THURSDAY"
  }
}
Changing weekStart is a global change that applies to the entire dataset.

The consecutiveMinutesOffLimit object must include consecutiveMinutesOffMin with the minimum number of consecutive minutes off.

1.1. Filter shifts with tags

RollingWindowRules can include or exclude shifts based on tags.

{
  "rollingWindowRules": [
    {
      "id": "2880ConsecutiveMinutesOffRollingWindow",
      "includeShiftTags": ["Part-time"],
      "rollingWindow": {
        "type": "DAILY",
        "size": 7
      }
    }
  ]
}
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.

1.2. Rule satisfiability

The satisfiability of the rule can be REQUIRED or PREFERRED. If omitted, REQUIRED is the default.

2. Required consecutive minutes off in rolling windows

When the satisfiability of the rule is REQUIRED, the Consecutive minutes off in rolling window not in preferred range for employee hard constraint is invoked, which makes sure the employee is assigned shifts with a break between two shifts that is not below the limit specified in consecutiveMinutesOffMin.

Shifts will be left unassigned if assigning them would break the Consecutive minutes off in rolling window not in preferred range for employee constraint.

2.1. Required consecutive minutes off in rolling windows example

In the following example, there are 7 shifts, 1 employee, and a rule that specifies employees must have 2280 consecutive minutes off in a rolling window of 7 days.

5 shifts are assigned, 2 shifts are not assigned.

required consecutive minutes off in a rolling window
  • 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 minutes off in a rolling window example"
    }
  },
  "modelInput": {
    "contracts": [
      {
        "id": "fullTimeContract",
        "rollingWindowRules": [
          {
            "id": "2880ConsecutiveMinutesOffRollingWindow",
            "rollingWindow": {
              "type": "DAILY",
              "size": 7
            },
            "consecutiveMinutesOffLimit":
            {
              "consecutiveMinutesOffMin": 2880
            },
            "satisfiability": "REQUIRED"
          }
        ]
      }
    ],
    "employees": [
      {
        "id": "Ann",
        "contracts": [
          "fullTimeContract"
        ]
      }
    ],
    "shifts": [
      {
        "id": "Mon",
        "start": "2027-02-01T09:00:00Z",
        "end": "2027-02-01T17:00:00Z"
      },
      {
        "id": "Tue",
        "start": "2027-02-02T09:00:00Z",
        "end": "2027-02-02T17:00:00Z"
      },
      {
        "id": "Wed",
        "start": "2027-02-03T09:00:00Z",
        "end": "2027-02-03T17:00:00Z"
      },
      {
        "id": "Thu",
        "start": "2027-02-04T09:00:00Z",
        "end": "2027-02-04T17:00:00Z"
      },
      {
        "id": "Fri",
        "start": "2027-02-05T09:00:00Z",
        "end": "2027-02-05T17:00:00Z"
      },
      {
        "id": "Sat",
        "start": "2027-02-06T09:00:00Z",
        "end": "2027-02-06T17:00:00Z"
      },
      {
        "id": "Sun",
        "start": "2027-02-07T09:00:00Z",
        "end": "2027-02-07T17: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 minutes off in a rolling window example",
    "submitDateTime": "2025-05-20T06:50:48.424569649Z",
    "startDateTime": "2025-05-20T06:51:00.55293692Z",
    "activeDateTime": "2025-05-20T06:51:00.704058777Z",
    "completeDateTime": "2025-05-20T06:51:31.731116902Z",
    "shutdownDateTime": "2025-05-20T06:51:32.123850049Z",
    "solverStatus": "SOLVING_COMPLETED",
    "score": "0hard/-2medium/0soft",
    "tags": [
      "system.profile:default"
    ],
    "validationResult": {
      "summary": "OK"
    }
  },
  "modelOutput": {
    "shifts": [
      {
        "id": "Mon",
        "employee": "Ann"
      },
      {
        "id": "Tue",
        "employee": "Ann"
      },
      {
        "id": "Wed",
        "employee": "Ann"
      },
      {
        "id": "Thu",
        "employee": "Ann"
      },
      {
        "id": "Fri",
        "employee": null
      },
      {
        "id": "Sat",
        "employee": null
      },
      {
        "id": "Sun",
        "employee": "Ann"
      }
    ]
  },
  "inputMetrics": {
    "employees": 1,
    "shifts": 7,
    "pinnedShifts": 0
  },
  "kpis": {
    "assignedShifts": 5,
    "unassignedShifts": 2,
    "workingTimeFairnessPercentage": null,
    "disruptionPercentage": 0.0,
    "averageDurationOfEmployeesPreferencesMet": null,
    "minimumDurationOfPreferencesMetAcrossEmployees": null,
    "averageDurationOfEmployeesUnpreferencesViolated": null,
    "maximumDurationOfUnpreferencesViolatedAcrossEmployees": null,
    "activatedEmployees": 1,
    "assignedMandatoryShifts": 5,
    "assignedOptionalShifts": 0,
    "assignedShiftGroups": null,
    "unassignedShiftGroups": null,
    "travelDistance": 0
  }
}

modelOutput contains the schedule with Ann assigned shifts and 2280 consecutive minutes (2 days) off.

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

KPIs provides the KPIs for the output including:

{
  "assignedShifts": 5,
  "unassignedShifts": 2,
  "activatedEmployees": 1,
  "assignedMandatoryShifts": 5
}

3. Preferred consecutive minutes off in rolling windows

When the satisfiability of the rule is PREFERRED, the Consecutive minutes off in rolling window not in required range for employee soft constraint is invoked.

{
  "contracts": [
    {
      "id": "fullTimeContract",
      "rollingWindowRules": [
        {
          "id": "2880ConsecutiveMinutesOffRollingWindow",
          "rollingWindow": {
            "type": "DAILY",
            "size": 7
          },
          "consecutiveMinutesOffLimit":
          {
            "consecutiveMinutesOffMin": 2880
          },
          "satisfiability": "PREFERRED"
        }
      ]
    }
  ]
}

If there is no alternative, shifts will still be assigned to employees even if assigning the shifts breaks the Consecutive minutes off in rolling window not in required range for employee soft constraint and the employee doesn’t get the minimum number of consecutive minutes off. 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. See Employee priority for more details.

3.1. Preferred consecutive minutes off in rolling windows example

In the following example, there are 7 shifts, 1 employee, and a rule with a preferred satisfiability that states employees should have 2280 consecutive minutes off in a rolling window of 7 days.

All 7 shifts are assigned, Ann does not get 2880 consecutive minutes off in the rolling window, and a soft penalty is applied to the dataset score.

preferred consecutive minutes off in a rolling window
  • 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 minutes off in a rolling window example"
    }
  },
  "modelInput": {
    "contracts": [
      {
        "id": "fullTimeContract",
        "rollingWindowRules": [
          {
            "id": "2880ConsecutiveMinutesOffRollingWindow",
            "rollingWindow": {
              "type": "DAILY",
              "size": 7
            },
            "consecutiveMinutesOffLimit":
            {
              "consecutiveMinutesOffMin": 2880
            },
            "satisfiability": "PREFERRED"
          }
        ]
      }
    ],
    "employees": [
      {
        "id": "Ann",
        "contracts": [
          "fullTimeContract"
        ]
      }
    ],
    "shifts": [
      {
        "id": "Mon",
        "start": "2027-02-01T09:00:00Z",
        "end": "2027-02-01T17:00:00Z"
      },
      {
        "id": "Tue",
        "start": "2027-02-02T09:00:00Z",
        "end": "2027-02-02T17:00:00Z"
      },
      {
        "id": "Wed",
        "start": "2027-02-03T09:00:00Z",
        "end": "2027-02-03T17:00:00Z"
      },
      {
        "id": "Thu",
        "start": "2027-02-04T09:00:00Z",
        "end": "2027-02-04T17:00:00Z"
      },
      {
        "id": "Fri",
        "start": "2027-02-05T09:00:00Z",
        "end": "2027-02-05T17:00:00Z"
      },
      {
        "id": "Sat",
        "start": "2027-02-06T09:00:00Z",
        "end": "2027-02-06T17:00:00Z"
      },
      {
        "id": "Sun",
        "start": "2027-02-07T09:00:00Z",
        "end": "2027-02-07T17: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": "Preferred consecutive minutes off in a rolling window example",
    "submitDateTime": "2025-05-20T07:44:16.673726099Z",
    "startDateTime": "2025-05-20T07:44:28.206497512Z",
    "activeDateTime": "2025-05-20T07:44:28.383105657Z",
    "completeDateTime": "2025-05-20T07:44:59.218846605Z",
    "shutdownDateTime": "2025-05-20T07:44:59.382971006Z",
    "solverStatus": "SOLVING_COMPLETED",
    "score": "0hard/0medium/-7680soft",
    "tags": [
      "system.profile:default"
    ],
    "validationResult": {
      "summary": "OK"
    }
  },
  "modelOutput": {
    "shifts": [
      {
        "id": "Mon",
        "employee": "Ann"
      },
      {
        "id": "Tue",
        "employee": "Ann"
      },
      {
        "id": "Wed",
        "employee": "Ann"
      },
      {
        "id": "Thu",
        "employee": "Ann"
      },
      {
        "id": "Fri",
        "employee": "Ann"
      },
      {
        "id": "Sat",
        "employee": "Ann"
      },
      {
        "id": "Sun",
        "employee": "Ann"
      }
    ]
  },
  "inputMetrics": {
    "employees": 1,
    "shifts": 7,
    "pinnedShifts": 0
  },
  "kpis": {
    "assignedShifts": 7,
    "unassignedShifts": 0,
    "workingTimeFairnessPercentage": null,
    "disruptionPercentage": 0.0,
    "averageDurationOfEmployeesPreferencesMet": null,
    "minimumDurationOfPreferencesMetAcrossEmployees": null,
    "averageDurationOfEmployeesUnpreferencesViolated": null,
    "maximumDurationOfUnpreferencesViolatedAcrossEmployees": null,
    "activatedEmployees": 1,
    "assignedMandatoryShifts": 7,
    "assignedOptionalShifts": 0,
    "assignedShiftGroups": null,
    "unassignedShiftGroups": null,
    "travelDistance": 0
  }
}

modelOutput contains the schedule with Ann assigned to all 7 shifts.

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

KPIs provides the KPIs for the output including:

{
  "assignedShifts": 7,
  "activatedEmployees": 1,
  "assignedMandatoryShifts": 7
}

4. Consecutive minutes off interval in a rolling window

If you have more complex consecutive minutes off rules to define, such as minimum two intervals of minimum 16 hours off in a rolling week, you can add these as multiple rules to consecutiveMinutesOffMinIntervals.

You cannot use consecutiveMinutesOffMin and consecutiveMinutesOffMinIntervals in the same rule.
{
  "modelInput": {
    "contracts": [
      {
        "id": "consecutive minutes off contract",
        "rollingWindowRules": [
          {
            "id": "2xMin8hOff and 1xMin12hOff",
            "rollingWindow": {
              "type": "WEEKLY",
              "size": 1
            },
            "consecutiveMinutesOffLimit":
            {
              "consecutiveMinutesOffMinIntervals": [
                {
                  "count": 2,
                  "consecutiveMinutesOffMin": 480
                },
                {
                  "count": 1,
                  "consecutiveMinutesOffMin": 720
                }
              ]
            },
            "satisfiability": "REQUIRED"
          }
        ]
      }
    ]
  }
}

consecutiveMinutesOffMinIntervals is a list that expects objects with the following properties:

  • count: The number of times the minimum consecutive minutes off must be met in the rolling window.

  • consecutiveMinutesOffMin: The minimum number of consecutive minutes off that must be met.

When defining multiple intervals, like in the example above, each consecutive minutes off span can only satisfy one interval. For example, if an employee must have 2x minimum 480 minutes off and 1x minimum 720 minutes off in a weekly rolling window, a single 1200-minute break cannot satisfy both the 480-minute and 720-minute intervals. Each period of time off satisfies at most one demand item. The employee needs enough qualifying periods of time off to cover all demands. If the number of periods of time off is lower than the number of demands, then the constraint can still be satisfied if all available periods match a demand.

For example, if an employee must have:

  • 1x minimum 480 minutes off

  • 1x minimum 120 minutes off in a weekly rolling window

then the constraint will penalize according to the following table.

actual time off penalize?

1x 200min off, 1x 500min off

no (matches both 120 minutes off and 480 minutes off demands)

1x 60min off, 1x 500min off

yes (doesn’t fully match 120 minutes off demand)

1x 200min

no (matches 120 minutes off demand. There is only 1 period of time off available, so it can satisfy at most 1 demand)

1x 30min

yes (the available break doesn’t satisfy any demand)

5. Consecutive minutes off conditionally in a rolling window

You can define a condition that has to be fulfilled in the rolling window before the rolling window rule is evaluated.

condition specifies the triggerLimit, type and includeShiftTags.

Further information about conditions:

type sets the triggerLimit unit, for instance, the example below requires at least two shifts to be worked with the tag Night shift in the rolling window before the condition is activated. The type can either be MIN_SHIFTS_WORKED or MIN_MINUTES_WORKED.

{
  "condition": {
    "triggerLimit": 2,
    "type": "MIN_SHIFTS_WORKED"
  }
}

includeShiftTags can be used to only include specific shifts. The example below limits the two shifts worked to "night shifts".

{
  "condition": {
    "triggerLimit": 2,
    "type": "MIN_SHIFTS_WORKED",
    "includeShiftTags": [ "Night shift" ]
  }
}

For example, an employee must have at least 120 consecutive minutes off in a rolling window, if they work ten hours (600 minutes) in that rolling window.

{
  "contracts": [
    {
      "id": "scheduleRestForLongShifts",
      "rollingWindowRules": [
        {
          "id": "120ConsecutiveMinutesOffRollingWindow",
          "rollingWindow": {
            "type": "HOURLY",
            "size": 12
          },
          "consecutiveMinutesOffLimit":
          {
            "consecutiveMinutesOffMin": 120
          },
          "satisfiability": "REQUIRED",
          "condition": {
            "triggerLimit": 600,
            "type": "MIN_MINUTES_WORKED"
          }
        }
      ]
    }
  ]
}

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' Time off.

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