Docs
  • Solver
  • Models
    • Field Service Routing
    • Employee Shift Scheduling
    • Pick-up and Delivery Routing
    • Task Scheduling
  • Platform
Start Free Trial
  • Employee Shift Scheduling
  • Lessons overview
  • Lesson 4
  • latest
    • latest
    • 1.35.x
    • 1.34.x

Employee Shift Scheduling

    • Introduction
    • Getting started: Hello world
    • Lessons overview
      • Lesson 1
      • Lesson 2
      • Lesson 3
      • Lesson 4
      • Interlude 1: Basic demo data
    • User guide
      • Terminology
      • Use case guide
      • Scheduling API concepts
      • Integration
      • Constraints
      • Using the API
        • Using the OpenAPI spec
        • API tooling
      • 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
      • Output datasets
        • Metadata
        • Model output
        • Input metrics
        • Key performance indicators (KPIs)
      • Metrics and optimization goals
      • Score analysis
      • Visualization
      • Efficiency X-Ray
      • Assignability analysis
    • Employee resource constraints
      • Employee availability and preferences
        • Employee availability
        • Employee preferences
      • Employee contracts
      • Employee priority
      • Pairing employees
      • Employee groups
      • Shift travel and locations
      • Shift Breaks
      • 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
        • Consecutive shifts 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
        • Cost groups
        • Employee rates
      • Demand-based scheduling
      • Priority and optional shifts
      • Skills and risk factors
      • Shift assignments
        • Shift selection
        • Employee selection
    • Manual intervention
    • Recommendations
    • Real-time planning
    • Scenarios
      • Configuring labor law compliance
      • Configuring employee well-being
      • Self-rostering and optimization
    • Changelog
    • Upgrade to the latest version
    • Feature requests

Lesson 4: Strict work limits

Introduction

In the previous lesson, we learned about employee contracts, which are used to group employees together based on the rules that apply to them. One of the most common types of rules which differs across employees is limits to work over a fixed calendar period such as a day, week, or month.

Rules which are tied to a fixed calendar period are called "period rules" in Timefold. Period rules are defined in contracts. They can be used to apply a number of different limits to employees per period, such as:

  • Time worked

  • Shifts worked (regardless of time in those shifts)

  • Days off

  • Time worked over weekends

In this lesson, we will focus on time worked in a certain period and learn how to think about this rule and implement it in Timefold. The other types of period rules are implemented in a very similar way, and are extensively covered in our technical documentation. Once you can implement one period rule, the rest are approachable in the same way.

If the limit is specified over a well-defined calendar period, then it is a good candidate for a period rule. If the limit is not tied to a well-defined period, and is for example an average over a period or worked over a sliding period, then it is not a period rule.

Calendar periods supported in period rules

By default, all period rules support:

  • DAY: one calendar day, every day of the schedule, starting at 00:00 and ending at 23:59:59.999

  • WEEK: one calendar week, every week of the schedule, by default starting every Monday at 00:00 and ending on Sunday at 23:59:59.999

  • MONTH: one calendar month, every month of the schedule, starting on the first day of the month at 00:00 and ending on the last day of the month at 23:59:59.999

  • YEAR: one calendar year, every year of the schedule, starting on January 1st at 00:00 and ending on December 31st at 23:59:59.999

  • SCHEDULE: covers the entire period of the schedule being planned.

  • MONDAY: active on any day which is a Monday, from 00:00 to 23:59:59.999.

  • TUESDAY: active on any day which is a Tuesday, from 00:00 to 23:59:59.999.

  • WEDNESDAY: active on any day which is a Wednesday, from 00:00 to 23:59:59.999.

  • THURSDAY: active on any day which is a Thursday, from 00:00 to 23:59:59.999.

  • FRIDAY: active on any day which is a Friday, from 00:00 to 23:59:59.999.

  • SATURDAY: active on any day which is a Saturday, from 00:00 to 23:59:59.999.

  • SUNDAY: active on any day which is a Sunday, from 00:00 to 23:59:59.999.

The period used for SCHEDULE is the entire period being actively planned. Most commonly, this is automatically calculated by Timefold. It is calculated to start at midnight before the earliest shift and end at midnight after the latest shift in the schedule. Optionally, it can be manually specified by the user by adding a planning window to the input dataset. For now, we will assume that the Timefold calculation is sufficient for our needs.
It is possible to adjust the week start to be any day of the week instead of the default Monday. This is described in the technical documentation for all period rules, and is not covered in this lesson. For now, we will assume that the week starts on Monday. If you wish to change the week start, see the technical documentation for any period rule, such as Minutes Worked Per Period.

Building a period rule

Minimum requirements

Period rules are defined in contracts, and, as covered in Lesson 3, apply to all employees who are assigned that contract.

At minimum, each period rule object in a contract must include an id and a period.

  • id can be any string of your choice. The id is the globally unique identifier for each individual period rule.

  • period must be a string which is one of the supported periods listed above. It defines the calendar period over which the rule applies.

{
  "contracts": [
    {
      "id": "fullTimeContract",
      "periodRules": [
        {
          "id": "periodRule1_fullTimeContract",
          "period": "DAY"
        },
        {
          "id": "periodRule2_fullTimeContract",
          "period": "WEEK"
        }
      ]
    },
    {
      "id": "partTimeContract",
      "periodRules": [
        {
          "id": "periodRule1_partTimeContract",
          "period": "DAY"
        },
        {
          "id": "periodRule2_partTimeContract",
          "period": "WEEK"
        }
      ]
    }
  ]
}
The id of each rule must be globally unique. This is true for every rule in a contract, not just period rules.

Limits

In their minimum form above, the period rules do not yet specify any limits over the specified period. A common limit used in contracts is the maximum time that an employee can work in a given period.

Let’s assume that we have two contracts in the schedule: a full-time contract and a part-time contract. The full-time contract has a maximum of ten hours of work per day and 50 hours of work per week. The part-time contract has a maximum of eight hours of work per day and 24 hours of work per week.

The minutes worked per period rule governs the amount of time that an employee can work in a given period. In order to apply this rule, the period rule must specify a minutesWorkedLimit object, which can include a minutesWorkedMax and/or a minutesWorkedMin. In this example, we will only use the minutesWorkedMax to limit the maximum time that an employee can work in a given period.

Most time-related limits are specified in minutes in Timefold. So our limits will be: 8 hours = 480 minutes, 10 hours = 600 minutes, 24 hours = 1,440 minutes, and 50 hours = 3,000 minutes.

Our period rules above can be updated to include the maximum time that an employee can work in a given period, as follows:

{
  "contracts": [
    {
      "id": "fullTimeContract",
      "periodRules": [
        {
          "id": "max10hoursPerDay_fullTimeContract",
          "period": "DAY",
          "minutesWorkedLimit": {
            "minutesWorkedMax": 600
          }
        },
        {
          "id": "max50hoursPerWeek_fullTimeContract",
          "period": "WEEK",
          "minutesWorkedLimit": {
            "minutesWorkedMax": 3000
          }
        }
      ]
    },
    {
      "id": "partTimeContract",
      "periodRules": [
        {
          "id": "max8hoursPerDay_partTimeContract",
          "period": "DAY",
          "minutesWorkedLimit": {
            "minutesWorkedMax": 480
          }
        },
        {
          "id": "max24hoursPerWeek_partTimeContract",
          "period": "WEEK",
          "minutesWorkedLimit": {
            "minutesWorkedMax": 1440
          }
        }
      ]
    }
  ]
}

Satisfiability

We must also add the satisfiability of the period rule. This tells the Timefold model if this rule is applied at the hard level (it is required to be followed) or at the soft level (it is a preference).

If you wish to revisit the difference between hard and soft constraints, see Lesson 1 for a refresher.

The satisfiability can be either REQUIRED or PREFERRED:

  • REQUIRED: hard constraint.

  • PREFERRED: soft constraint.

Let’s assume that for both types of employees, the daily work limit is a soft constraint, but the weekly work limit is a hard constraint. Our period rules above can be updated to include the satisfiability of the rule, as follows:

{
  "contracts": [
    {
      "id": "fullTimeContract",
      "periodRules": [
        {
          "id": "max10hoursPerDay_fullTimeContract",
          "period": "DAY",
          "minutesWorkedLimit": {
            "minutesWorkedMax": 600
          },
          "satisfiability": "PREFERRED"
        },
        {
          "id": "max50hoursPerWeek_fullTimeContract",
          "period": "WEEK",
          "minutesWorkedLimit": {
            "minutesWorkedMax": 3000
          },
          "satisfiability": "REQUIRED"
        }
      ]
    },
    {
      "id": "partTimeContract",
      "periodRules": [
        {
          "id": "max8hoursPerDay_partTimeContract",
          "period": "DAY",
          "minutesWorkedLimit": {
            "minutesWorkedMax": 480
          },
          "satisfiability": "PREFERRED"
        },
        {
          "id": "max24hoursPerWeek_partTimeContract",
          "period": "WEEK",
          "minutesWorkedLimit": {
            "minutesWorkedMax": 1440
          },
          "satisfiability": "REQUIRED"
        }
      ]
    }
  ]
}

This is a fully implemented period rule, which will limit the working time of the employees.

Practical example

This example has two employees. Beth can work 50 hours per week, and Ann can work 24 hours per week. The schedule has ten shifts, each of which is eight hours long. Due to the period rules in each employee’s contract, and the shift make-up, Ann can work three shifts and Beth can work five. Therefore, two shifts remain unstaffed.

Period rules: Beth works five shifts and Ann works three while two shifts stay unassigned
  • Input

  • Output

Try this example in Timefold Platform by saving this JSON into a file called sample.json and making 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": "Lesson 4: Period rules"
    }
  },
  "modelInput": {
    "contracts": [
      {
        "id": "fullTimeContract",
        "periodRules": [
          {
            "id": "max10hoursPerDay_fullTimeContract",
            "period": "DAY",
            "minutesWorkedLimit": {
              "minutesWorkedMax": 600
            },
            "satisfiability": "PREFERRED"
          },
          {
            "id": "max50hoursPerWeek_fullTimeContract",
            "period": "WEEK",
            "minutesWorkedLimit": {
              "minutesWorkedMax": 3000
            },
            "satisfiability": "REQUIRED"
          }
        ]
      },
      {
        "id": "partTimeContract",
        "periodRules": [
          {
            "id": "max8hoursPerDay_partTimeContract",
            "period": "DAY",
            "minutesWorkedLimit": {
              "minutesWorkedMax": 480
            },
            "satisfiability": "PREFERRED"
          },
          {
            "id": "max24hoursPerWeek_partTimeContract",
            "period": "WEEK",
            "minutesWorkedLimit": {
              "minutesWorkedMax": 1440
            },
            "satisfiability": "REQUIRED"
          }
        ]
      }
    ],
    "employees": [
      {
        "id": "Beth",
        "contracts": [
          "fullTimeContract"
        ],
        "skills": [
          {
            "id": "Night"
          },
          {
            "id": "Bakery"
          }
        ]
      },
      {
        "id": "Ann",
        "contracts": [
          "partTimeContract"
        ],
        "skills": [
          {
            "id": "Night"
          },
          {
            "id": "Bakery"
          }
        ],
        "prohibitedRiskFactors": [
          "Shellfish allergy"
        ]
      }
    ],
    "shifts": [
      {
        "id": "Mon Night Bakery Shellfish shift",
        "start": "2027-02-01T00:00:00Z",
        "end": "2027-02-01T08:00:00Z",
        "requiredSkills": [
          "Night",
          "Bakery"
        ],
        "riskFactors": [
          "Shellfish allergy"
        ]
      },
      {
        "id": "Mon Night Bakery shift 2",
        "start": "2027-02-01T00:00:00Z",
        "end": "2027-02-01T08:00:00Z",
        "requiredSkills": [
          "Night",
          "Bakery"
        ]
      },
      {
        "id": "Tues Night Bakery shift",
        "start": "2027-02-02T00:00:00Z",
        "end": "2027-02-02T08:00:00Z",
        "requiredSkills": [
          "Night",
          "Bakery"
        ]
      },
      {
        "id": "Tues Night Bakery shift 2",
        "start": "2027-02-02T00:00:00Z",
        "end": "2027-02-02T08:00:00Z",
        "requiredSkills": [
          "Night",
          "Bakery"
        ]
      },
      {
        "id": "Wed Night Bakery shift",
        "start": "2027-02-03T00:00:00Z",
        "end": "2027-02-03T08:00:00Z",
        "requiredSkills": [
          "Night",
          "Bakery"
        ]
      },
      {
        "id": "Wed Night Bakery shift 2",
        "start": "2027-02-03T00:00:00Z",
        "end": "2027-02-03T08:00:00Z",
        "requiredSkills": [
          "Night",
          "Bakery"
        ]
      },
      {
        "id": "Thurs Night Bakery shift",
        "start": "2027-02-04T00:00:00Z",
        "end": "2027-02-04T08:00:00Z",
        "requiredSkills": [
          "Night",
          "Bakery"
        ]
      },
      {
        "id": "Thurs Night Bakery shift 2",
        "start": "2027-02-04T00:00:00Z",
        "end": "2027-02-04T08:00:00Z",
        "requiredSkills": [
          "Night",
          "Bakery"
        ]
      },
      {
        "id": "Fri Night Bakery shift",
        "start": "2027-02-05T00:00:00Z",
        "end": "2027-02-05T08:00:00Z",
        "requiredSkills": [
          "Night",
          "Bakery"
        ]
      },
      {
        "id": "Fri Night Bakery shift 2",
        "start": "2027-02-05T00:00:00Z",
        "end": "2027-02-05T08:00:00Z",
        "requiredSkills": [
          "Night",
          "Bakery"
        ]
      }
    ]
  }
}
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": "b9c26bc4-8190-44da-aa76-7a4a25255672",
    "originId": "b9c26bc4-8190-44da-aa76-7a4a25255672",
    "name": "Lesson 4: Period rules",
    "submitDateTime": "2026-09-22T15:28:49.230456143Z",
    "startDateTime": "2026-09-22T15:28:59.44407139Z",
    "activeDateTime": "2026-09-22T15:28:59.547425467Z",
    "completeDateTime": "2026-09-22T15:29:29.963247863Z",
    "shutdownDateTime": "2026-09-22T15:29:29.96326503Z",
    "solverStatus": "SOLVING_COMPLETED",
    "score": "0hard/-2medium/0soft",
    "tags": [
      "system.type:from-request",
      "system.profile:Standard profile"
    ],
    "validationResult": {
      "summary": "OK"
    }
  },
  "modelOutput": {
    "shifts": [
      {
        "id": "Mon Night Bakery Shellfish shift",
        "employee": "Beth"
      },
      {
        "id": "Mon Night Bakery shift 2",
        "employee": "Ann"
      },
      {
        "id": "Tues Night Bakery shift",
        "employee": "Beth"
      },
      {
        "id": "Tues Night Bakery shift 2",
        "employee": "Ann"
      },
      {
        "id": "Wed Night Bakery shift",
        "employee": "Beth"
      },
      {
        "id": "Wed Night Bakery shift 2",
        "employee": "Ann"
      },
      {
        "id": "Thurs Night Bakery shift",
        "employee": "Beth"
      },
      {
        "id": "Thurs Night Bakery shift 2"
      },
      {
        "id": "Fri Night Bakery shift",
        "employee": "Beth"
      },
      {
        "id": "Fri Night Bakery shift 2"
      }
    ],
    "employees": [
      {
        "id": "Beth",
        "metrics": {
          "assignedShifts": 5,
          "durationWorked": "PT40H",
          "overtimeThresholdDuration": "PT50H",
          "overtimeWorked": "PT0S",
          "maximumAvailabilityDuration": "PT50H"
        }
      },
      {
        "id": "Ann",
        "metrics": {
          "assignedShifts": 3,
          "durationWorked": "PT24H",
          "overtimeThresholdDuration": "PT24H",
          "overtimeWorked": "PT0S",
          "maximumAvailabilityDuration": "PT24H"
        }
      }
    ],
    "generatedShifts": []
  },
  "inputMetrics": {
    "employees": 2,
    "shifts": 10,
    "pinnedShifts": 0,
    "mandatoryShifts": 10,
    "optionalShifts": 0
  },
  "kpis": {
    "assignedShifts": 8,
    "unassignedShifts": 2,
    "disruptionPercentage": 0,
    "activatedEmployees": 2,
    "assignedMandatoryShifts": 8
  },
  "run": {
    "id": "b9c26bc4-8190-44da-aa76-7a4a25255672",
    "originId": "b9c26bc4-8190-44da-aa76-7a4a25255672",
    "name": "Lesson 4: Period rules",
    "submitDateTime": "2026-09-22T15:28:49.230456143Z",
    "startDateTime": "2026-09-22T15:28:59.44407139Z",
    "activeDateTime": "2026-09-22T15:28:59.547425467Z",
    "completeDateTime": "2026-09-22T15:29:29.963247863Z",
    "shutdownDateTime": "2026-09-22T15:29:29.96326503Z",
    "solverStatus": "SOLVING_COMPLETED",
    "score": "0hard/-2medium/0soft",
    "tags": [
      "system.type:from-request",
      "system.profile:Standard profile"
    ],
    "validationResult": {
      "summary": "OK"
    }
  }
}

modelOutput contains the schedule with Beth assigned to five shifts and Ann assigned to three. Thurs Night Bakery shift 2 and Fri Night Bakery shift 2 remain unassigned, which gives a score of 0hard/-2medium/0soft.

Approaching other period rules

The other period rules follow a very similar approach to the one we have just covered. The main difference is that instead of specifying a minutesWorkedLimit, you must specify the appropriate limit for the type of period rule you are implementing. The limits are stated in the technical documentation for period rules:

  • Time worked

  • Shifts worked (regardless of time in those shifts)

  • Days worked (regardless of time or shifts on those days)

  • Days off

  • Consecutive days off

  • Time worked over weekends

  • Weekends worked (regardless of time)

  • Consecutive weekends worked (regardless of time)

  • Consecutive weekends off

Conclusion

In this lesson, we learned about:

  • How a period rule applies limits to calendar periods

  • How to implement a period rule in Timefold

  • How to implement a limit on time worked in a period rule

  • How to approach other types of period rules, which are implemented in a very similar way to the time worked limit.

Next

  • Proceed to Interlude: Basic demo data to learn about the Timefold basic demo example, which you should be able to fully comprehend based on Lessons 1 to 4.

  • Discover more in-depth technical details about period rules in their technical documentation linked above, such as the Minutes Worked Per Period documentation of the user guide.

  • Alternatively, go back to the Lessons overview to choose a different lesson to continue with.

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