Docs
  • Solver
  • Models
    • Field Service Routing
    • Employee Shift Scheduling
  • Platform
Try models
  • Employee Shift Scheduling
  • Employee resource constraints
  • Employee availability

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

Employee availability

Employee availability determines when employees can and cannot be scheduled for shifts and allows employees to express preferences for which shifts they work.

Employees may need days off (or parts of days) when they have other commitments, such as medical appointments or caring for family members. Employees also have vacation days (or PTO), public holidays, and other paid days off.

Contractors might only be required or available for certain periods of time.

Employees might prefer to work certain shifts, at certain locations, or to perform certain roles.

For an employee shift schedule to be feasible, the employee shift scheduling solution must include availability information, and allowing employees to set preferences for when they work improves job satisfaction and performance at work.

This guide explains how to manage employee availability and preferences with the following examples:

  • Defining employee availability

  • Employee unavailability times

  • Employee availability times

  • Filtering availability with tags

  • Defining employee preferences

  • Employee preferred times

  • Employee preferred time not available

  • Employees unpreferred times

  • Filtering preferences with tags

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. Defining employee availability

Defining either availableTimeSpans or unavailableTimeSpans results in times when an employee is both available and also unavailable. With availableTimeSpans any time that is not included is time when the employee is unavailable, and with unavailableTimeSpans any time that is not included is time when the employee is available.

We recommend using:

  • unavailableTimeSpans for full-time employees who are usually available for any shift and have occasional periods of unavailability.

  • availableTimeSpans for contractors who are only available for specific periods of time.

2. Employee unavailability times

Employees are considered to be available for any shifts in the schedule unless unavailable time spans are defined.

Beth is a full-time employee and is generally available for any shift, however, on Friday she has a commitment that means she is not available to cover a shift.

employee unavailability

An employee’s unavailability is defined by adding an unavailableTimeSpans array to the employee with a start and an end time for the period they are unavailable.

Unavailable periods can span multiple days.

{
  "employees": [
    {
      "id": "Beth",
      "unavailableTimeSpans": [
        {
          "start": "2027-02-05T00:00:00Z",
          "end": "2027-02-06T00:00:00Z"
        }
      ]
    }
  ]
}
  • start is a date and time (in ISO 8601 date time with offset to UTC format) for the start of the period the employee is unavailable.

  • end is a date and time in ISO 8601 with date time offset to UTC for the end of the period the employee is unavailable.

  • 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": "Unavailability example"
    }
  },
  "modelInput": {
    "employees": [
      {
        "id": "Beth",
        "unavailableTimeSpans": [
          {
            "start": "2027-02-05T00:00:00Z",
            "end": "2027-02-06T00:00:00Z"
          }
        ]
      }
    ],
    "shifts": [
      {
        "id": "2027-02-01",
        "start": "2027-02-01T09:00:00Z",
        "end": "2027-02-01T17:00:00Z"
      },
      {
        "id": "2027-02-02",
        "start": "2027-02-02T09:00:00Z",
        "end": "2027-02-02T17:00:00Z"
      },
      {
        "id": "2027-02-03",
        "start": "2027-02-03T09:00:00Z",
        "end": "2027-02-03T17:00:00Z"
      },
      {
        "id": "2027-02-04",
        "start": "2027-02-04T09:00:00Z",
        "end": "2027-02-04T17:00:00Z"
      },
      {
        "id": "2027-02-05",
        "start": "2027-02-05T09:00:00Z",
        "end": "2027-02-05T17: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": "Unavailability example",
    "submitDateTime": "2024-09-12T09:45:46.822999677Z",
    "startDateTime": "2024-09-12T09:45:52.628925423Z",
    "activeDateTime": "2024-09-12T09:45:52.728925423Z",
    "completeDateTime": "2024-09-12T09:50:53.058023049Z",
    "shutdownDateTime": "2024-09-12T09:50:53.158023049Z",
    "solverStatus": "SOLVING_COMPLETED",
    "score": "0hard/-10000medium/0soft",
    "tags": null,
    "validationResult": {
      "summary": "OK"
    }
  },
  "modelOutput": {
    "shifts": [
      {
        "id": "2027-02-01",
        "employee": "Beth"
      },
      {
        "id": "2027-02-02",
        "employee": "Beth"
      },
      {
        "id": "2027-02-03",
        "employee": "Beth"
      },
      {
        "id": "2027-02-04",
        "employee": "Beth"
      },
      {
        "id": "2027-02-05",
        "employee": null
      }
    ]
  },
  "kpis": {
    "unassignedShifts": 1
  }
}

modelOutput contains the employee shift schedule with Beth assigned to the shifts when she is available.

In this example, the Friday shift is left unassigned. Timefold will assign shifts to employees who are available, however, assigning the shift to Beth would break a hard constraint and make the plan infeasible. Leaving the shift unassigned breaks a medium constraint but the plan is still feasible.

Learn about the hard, medium, and soft constraints in Employee Shift Scheduling model.

3. Employee availability times

Not all employees work full-time for a company. Contractors might only be required or are only available for certain periods of time.

Carl is a contractor who works when Beth is unavailable.

employee availability

An employee’s availability can be defined by adding an availableTimeSpans array to the employee with a start and an end time for the period they are available.

Available periods can span multiple days.

{
  "employees": [
    {
      "id": "Carl",
      "availableTimeSpans": [
        {
          "start": "2027-02-02T00:00:00Z",
          "end": "2027-02-06T00:00:00Z"
        }
      ]
    }
  ]
}
  • start is a date and time (in ISO 8601 date time with offset to UTC format) for the start of the period the employee is available.

  • end is a date and time in ISO 8601 with date time offset to UTC for the end of the period the employee is available.

  • 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": "Availability example"
    }
  },
  "modelInput": {
    "employees": [
      {
        "id": "Beth",
        "unavailableTimeSpans": [
          {
            "start": "2027-02-02T00:00:00Z",
            "end": "2027-02-08T00:00:00Z"
          }
        ]
      },
      {
        "id": "Carl",
        "availableTimeSpans": [
          {
            "start": "2027-02-02T00:00:00Z",
            "end": "2027-02-06T00:00:00Z"
          }
        ]
      }
    ],
    "shifts": [
      {
        "id": "2027-02-01",
        "start": "2027-02-01T09:00:00Z",
        "end": "2027-02-01T17:00:00Z"
      },
      {
        "id": "2027-02-02",
        "start": "2027-02-02T09:00:00Z",
        "end": "2027-02-02T17:00:00Z"
      },
      {
        "id": "2027-02-03",
        "start": "2027-02-03T09:00:00Z",
        "end": "2027-02-03T17:00:00Z"
      },
      {
        "id": "2027-02-04",
        "start": "2027-02-04T09:00:00Z",
        "end": "2027-02-04T17:00:00Z"
      },
      {
        "id": "2027-02-05",
        "start": "2027-02-05T09:00:00Z",
        "end": "2027-02-05T17: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": "Availability example",
    "submitDateTime": "2024-09-12T09:55:53.15634866Z",
    "startDateTime": "2024-09-12T09:55:58.934451453Z",
    "activeDateTime": "2024-09-12T09:55:59.034451453Z",
    "completeDateTime": "2024-09-12T10:00:59.512605369Z",
    "shutdownDateTime": "2024-09-12T10:00:59.612605369Z",
    "solverStatus": "SOLVING_COMPLETED",
    "score": "0hard/0medium/0soft",
    "tags": null,
    "validationResult": {
      "summary": "OK"
    }
  },
  "modelOutput": {
    "shifts": [
      {
        "id": "2027-02-01",
        "employee": "Beth"
      },
      {
        "id": "2027-02-02",
        "employee": "Carl"
      },
      {
        "id": "2027-02-03",
        "employee": "Carl"
      },
      {
        "id": "2027-02-04",
        "employee": "Carl"
      },
      {
        "id": "2027-02-05",
        "employee": "Carl"
      }
    ]
  },
  "kpis": {
    "unassignedShifts": 0
  }
}

modelOutput contains the employee shift schedule with Beth and Carl assigned to shifts that match their availability as defined by Ann’s unavailableTimeSpan and Carl’s availableTimeSpan.

4. Filtering availability with tags

Tags can be added to availableTimeSpans and unavailableTimeSpans to control which shifts the availability time spans apply to.

For instance, Beth is unavailable for a week, and her shifts must be assigned to a contractor to avoid assigning another full-time employee (and leaving that employee’s regular shifts unassigned).

The contractor who is assigned the shifts must be able to travel to the company’s central office. Beth’s regular shifts are tagged with "location central":

{
  "shifts": [
    {
      "id": "2027-02-01",
      "start": "2027-02-01T09:00:00Z",
      "end": "2027-02-01T17:00:00Z",
      "tags": [
        "location central"
      ]
    }
  ]
}

Carl and Ann are both available. Carl can travel to the central office and his availability includes "includeShiftTags": [ "location central" ].

Ann is also available, but she cannot travel to the central office, so her availability includes "excludeShiftTags": [ "location central" ].

includeShiftTags and excludeShiftTags can both be used in the same dataset, but they cannot be used in combination. ie, because Carl’s availableTimeSpans uses includeShiftTags it cannot also use excludeShiftTags. Similarly, because Ann’s availableTimeSpans uses excludeShiftTags it cannot also use includeShiftTags.
{
  "employees": [
    {
      "id": "Beth",
      "unavailableTimeSpans": [
        {
          "start": "2027-02-01T00:00:00Z",
          "end": "2027-02-06T00:00:00Z"
        }
      ]
    },
    {
      "id": "Carl",
      "availableTimeSpans": [
        {
          "start": "2027-02-02T00:00:00Z",
          "end": "2027-02-06T00:00:00Z",
          "includeShiftTags": [ "location central" ]
        }
      ]
    },
    {
      "id": "Ann",
      "availableTimeSpans": [
        {
          "start": "2027-02-02T00:00:00Z",
          "end": "2027-02-06T00:00:00Z",
          "excludeShiftTags": [ "location central" ]
        }
      ]
    }
  ]
}

In this instance, Carl is assigned the shifts because he can travel to the central office, however, Carl isn’t available for the Monday shift. Even though Ann is available on Monday, she cannot travel to the central office, and she is not assigned the shift.

employee availability with tags

  • 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": "Availability with Tags example"
    }
  },
  "modelInput": {
    "employees": [
      {
        "id": "Beth",
        "unavailableTimeSpans": [
          {
            "start": "2027-02-01T00:00:00Z",
            "end": "2027-02-08T00:00:00Z"
          }
        ]
      },
      {
        "id": "Carl",
        "availableTimeSpans": [
          {
            "start": "2027-02-02T00:00:00Z",
            "end": "2027-02-06T00:00:00Z",
            "includeShiftTags": [ "location central" ]
          }
        ]
      },
      {
        "id": "Ann",
        "availableTimeSpans": [
          {
            "start": "2027-02-01T00:00:00Z",
            "end": "2027-02-06T00:00:00Z",
            "excludeShiftTags": [ "location central" ]
          }
        ]
      }
    ],
    "shifts": [
      {
        "id": "2027-02-01",
        "start": "2027-02-01T09:00:00Z",
        "end": "2027-02-01T17:00:00Z",
        "tags": [
          "location central"
        ]
      },
      {
        "id": "2027-02-02",
        "start": "2027-02-02T09:00:00Z",
        "end": "2027-02-02T17:00:00Z",
        "tags": [
          "location central"
        ]
      },
      {
        "id": "2027-02-03",
        "start": "2027-02-03T09:00:00Z",
        "end": "2027-02-03T17:00:00Z",
        "tags": [
          "location central"
        ]
      },
      {
        "id": "2027-02-04",
        "start": "2027-02-04T09:00:00Z",
        "end": "2027-02-04T17:00:00Z",
        "tags": [
          "location central"
        ]
      },
      {
        "id": "2027-02-05",
        "start": "2027-02-05T09:00:00Z",
        "end": "2027-02-05T17:00:00Z",
        "tags": [
          "location central"
        ]
      }
    ]
  }
}
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": "Availability with Tags example",
    "submitDateTime": "2024-09-24T05:10:39.287389671Z",
    "startDateTime": "2024-09-24T05:10:47.173446864Z",
    "activeDateTime": "2024-09-24T05:10:47.273446864Z",
    "completeDateTime": "2024-09-24T05:15:47.71357411Z",
    "shutdownDateTime": "2024-09-24T05:15:47.81357411Z",
    "solverStatus": "SOLVING_COMPLETED",
    "score": "0hard/-1medium/0soft",
    "tags": null,
    "validationResult": {
      "summary": "OK"
    }
  },
  "modelOutput": {
    "shifts": [
      {
        "id": "2027-02-01",
        "employee": null
      },
      {
        "id": "2027-02-02",
        "employee": "Carl"
      },
      {
        "id": "2027-02-03",
        "employee": "Carl"
      },
      {
        "id": "2027-02-04",
        "employee": "Carl"
      },
      {
        "id": "2027-02-05",
        "employee": "Carl"
      }
    ]
  },
  "kpis": {
    "unassignedShifts": 1
  }
}

modelOutput contains the employee shift schedule with Carl assigned to the shifts when he is available, and the Monday shift left unassigned because Beth is unavailable and Ann’s availability isn’t for shifts tagged "location central".

If shifts have multiple tags, you decide whether to match ALL or ANY of the tags based on employee availability by including shiftTagMatches.

{
  "availableTimeSpans": [
    {
      "start": "2027-02-01T00:00:00Z",
      "end": "2027-02-03T00:00:00Z",
      "includeShiftTags": [
        "department a",
        "location central"
      ],
      "shiftTagMatches": "ALL"
    }
  ]
}

With shiftTagMatches set to "ALL", a shift must include all the tags defined by the employee to match.

With shiftTagMatches set to "ANY", a shift must include at least one of the tags defined by the employee to match.

If shiftTagMatches is not included in the modelInput, all tags must match.

5. Defining employee preferences

Employee preferences can be expressed as both preferred (positive) and unpreferred (negative). Typically, we suggest expressing preferences in terms of the employee’s intent.

For instance, if the employee prefers not to work on Thursday, define an unpreferredTimeSpans for Thursday. Do not define a preferredTimeSpans for every day except Thursday.

If an employee prefers to work in department A, define a preferredTimeSpans for department A. Do not define a unpreferredTimeSpans for every department except department A.

6. Employee preferred times

Employees are considered to be available for any shifts in the schedule unless unavailable time spans are defined.

See Employee availability for more information.

Ann and Beth are both full-time employees.

  • Ann prefers to work the day shift, 08:00 until 16:00.

  • Beth prefers to work the evening shift, 16:00 to 00:00.

employee preferences

Employees' preferences are defined by adding a preferredTimeSpan array to the employee with a start and an end time for their preferred period.

{
  "employees": [
    {
      "id": "Ann",
      "preferredTimeSpans": [
        {
          "start": "2027-02-01T08:00:00Z",
          "end": "2027-02-01T16:00:00Z"
        },
        {
          "start": "2027-02-02T08:00:00Z",
          "end": "2027-02-02T16:00:00Z"
        }
      ]
    }
  ]
}
  • start is a date and time (in ISO 8601 date time with offset to UTC format) for the start of the period the employee prefers.

  • end is a date and time (in ISO 8601 date time with offset to UTC format) for the end of the period the employee prefers.

  • 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 time spans example"
    }
  },
  "modelInput": {
    "employees": [
      {
        "id": "Ann",
        "preferredTimeSpans": [
          {
            "start": "2027-02-01T08:00:00Z",
            "end": "2027-02-01T16:00:00Z"
          },
          {
            "start": "2027-02-02T08:00:00Z",
            "end": "2027-02-02T16:00:00Z"
          }
        ]
      },
      {
        "id": "Beth",
        "preferredTimeSpans": [
          {
            "start": "2027-02-01T16:00:00Z",
            "end": "2027-02-02T00:00:00Z"
          },
          {
            "start": "2027-02-02T16:00:00Z",
            "end": "2027-02-03T00:00:00Z"
          }
        ]
      }
    ],
    "shifts": [
      {
        "id": "Mon Day",
        "start": "2027-02-01T08:00:00Z",
        "end": "2027-02-01T16:00:00Z"
      },
      {
        "id": "Mon Evening",
        "start": "2027-02-01T16:00:00Z",
        "end": "2027-02-02T00:00:00Z"
      },
      {
        "id": "Tue Day",
        "start": "2027-02-02T08:00:00Z",
        "end": "2027-02-02T16:00:00Z"
      },
      {
        "id": "Tue Evening",
        "start": "2027-02-02T16:00:00Z",
        "end": "2027-02-03T00: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": "Preferred time spans example",
    "submitDateTime": "2024-09-19T06:23:13.430778281Z",
    "startDateTime": "2024-09-19T06:23:18.972386292Z",
    "activeDateTime": "2024-09-19T06:23:19.072386292Z",
    "completeDateTime": "2024-09-19T06:28:19.350143099Z",
    "shutdownDateTime": "2024-09-19T06:28:19.450143099Z",
    "solverStatus": "SOLVING_COMPLETED",
    "score": "0hard/0medium/3840soft",
    "tags": null,
    "validationResult": {
      "summary": "OK"
    }
  },
  "modelOutput": {
    "shifts": [
      {
        "id": "Mon Day",
        "employee": "Ann"
      },
      {
        "id": "Tue Evening",
        "employee": "Beth"
      },
      {
        "id": "Tue Day",
        "employee": "Ann"
      },
      {
        "id": "Tue Evening",
        "employee": "Beth"
      }
    ]
  },
  "kpis": {
    "unassignedShifts": 0
  }
}

modelOutput contains the employee schedule with both Ann and Beth assigned to shifts during their preferred times.

7. Employee preferred time not available

It is not always possible to schedule employees during their preferred time spans.

In a case where both Ann and Beth prefer the same shift. Only one of them will be assigned the day shift, and the other will be assigned the evening shift.

employee preferences with a conflict

See Employee availability for information about specifying availability and unavailability.
  • 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 time spans with conflict example"
    }
  },
  "modelInput": {
    "contracts": [
      {
        "id": "Default contract",
        "periodRules": [
          {
            "id": "singleShiftPerDay",
            "period": "DAY",
            "shiftsWorkedMax": 1
          }
        ]
      }
    ],
    "employees": [
      {
        "id": "Ann",
        "contracts": [
          "Default contract"
        ],
        "preferredTimeSpans": [
          {
            "start": "2027-02-01T08:00:00Z",
            "end": "2027-02-01T16:00:00Z"
          },
          {
            "start": "2027-02-02T08:00:00Z",
            "end": "2027-02-02T16:00:00Z"
          }
        ]
      },
      {
        "id": "Beth",
        "contracts": [
          "Default contract"
        ],
        "preferredTimeSpans": [
          {
            "start": "2027-02-01T08:00:00Z",
            "end": "2027-02-01T16:00:00Z"
          },
          {
            "start": "2027-02-02T08:00:00Z",
            "end": "2027-02-02T16:00:00Z"
          }
        ]
      }
    ],
    "shifts": [
      {
        "id": "2027-02-01-day",
        "start": "2027-02-01T08:00:00Z",
        "end": "2027-02-01T16:00:00Z"
      },
      {
        "id": "2027-02-01-evening",
        "start": "2027-02-01T16:00:00Z",
        "end": "2027-02-02T00:00:00Z"
      },
      {
        "id": "2027-02-02-day",
        "start": "2027-02-02T08:00:00Z",
        "end": "2027-02-02T16:00:00Z"
      },
      {
        "id": "2027-02-02-evening",
        "start": "2027-02-02T16:00:00Z",
        "end": "2027-02-03T00: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": "Preferred time spans with conflict example",
    "submitDateTime": "2024-09-19T07:07:13.411491728Z",
    "startDateTime": "2024-09-19T07:07:21.630221733Z",
    "activeDateTime": "2024-09-19T07:07:21.730221733Z",
    "completeDateTime": "2024-09-19T07:12:22.013369565Z",
    "shutdownDateTime": "2024-09-19T07:12:22.113369565Z",
    "solverStatus": "SOLVING_COMPLETED",
    "score": "0hard/0medium/1920soft",
    "tags": null,
    "validationResult": {
      "summary": "OK"
    }
  },
  "modelOutput": {
    "shifts": [
      {
        "id": "2027-02-01-day",
        "employee": "Ann"
      },
      {
        "id": "2027-02-01-evening",
        "employee": "Beth"
      },
      {
        "id": "2027-02-02-day",
        "employee": "Ann"
      },
      {
        "id": "2027-02-02-evening",
        "employee": "Beth"
      }
    ]
  },
  "kpis": {
    "unassignedShifts": 0
  }
}

modelOutput contains the employee schedule. Ann is scheduled her preferred shifts, but Beth is not.

8. Employees unpreferred times

Employee preferences can also be expressed as time spans when they prefer not to work, but are available to work if required.

If we look at the first example again, but this time state Ann’s and Beth’s preferences in terms of times they would prefer not to work.

Ann and Beth are both full-time employees.

  • Ann prefers not to work the evening shift, 16:00 to 00:00.

  • Beth prefers not to work the day shift, 08:00 until 16:00.

In the first example, we defined these time spans as preferred, not unpreferred. By defining the unpreferred times, we are not limiting Ann and Beth to a single shift. For instance, if the company has a night shift, Ann’s preference not to work the evening shift, leaves her free to work either the day or night shift.

Similarly, Beth’s preference not to work the day shift, leaves her free to work either the evening or night shift.

{
  "employees": [
    {
      "id": "Ann",
      "unpreferredTimeSpans": [
        {
          "start": "2027-02-01T16:00:00Z",
          "end": "2027-02-02T00:00:00Z"
        },
        {
          "start": "2027-02-02T16:00:00Z",
          "end": "2027-02-03T00:00:00Z"
        }
      ]
    }
  ]
}

The following example, results in Ann and Beth not being assigned shifts during their unpreferred times.

  • 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 time spans example"
    }
  },
  "modelInput": {
    "employees": [
      {
        "id": "Ann",
        "unpreferredTimeSpans": [
          {
            "start": "2027-02-01T16:00:00Z",
            "end": "2027-02-02T00:00:00Z"
          },
          {
            "start": "2027-02-02T16:00:00Z",
            "end": "2027-02-03T00:00:00Z"
          }
        ]
      },
      {
        "id": "Beth",
        "unpreferredTimeSpans": [
          {
            "start": "2027-02-01T08:00:00Z",
            "end": "2027-02-01T16:00:00Z"
          },
          {
            "start": "2027-02-02T08:00:00Z",
            "end": "2027-02-02T16:00:00Z"
          }
        ]
      }
    ],
    "shifts": [
      {
        "id": "Mon Day",
        "start": "2027-02-01T08:00:00Z",
        "end": "2027-02-01T16:00:00Z"
      },
      {
        "id": "Mon Evening",
        "start": "2027-02-01T16:00:00Z",
        "end": "2027-02-02T00:00:00Z"
      },
      {
        "id": "Tue Day",
        "start": "2027-02-02T08:00:00Z",
        "end": "2027-02-02T16:00:00Z"
      },
      {
        "id": "Tue Evening",
        "start": "2027-02-02T16:00:00Z",
        "end": "2027-02-03T00: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": "Unpreferred time spans example",
    "submitDateTime": "2024-09-20T06:56:27.642773329Z",
    "startDateTime": "2024-09-20T06:56:33.281870696Z",
    "activeDateTime": "2024-09-20T06:56:33.381870696Z",
    "completeDateTime": "2024-09-20T07:01:33.635593953Z",
    "shutdownDateTime": "2024-09-20T07:01:33.735593953Z",
    "solverStatus": "SOLVING_COMPLETED",
    "score": "0hard/0medium/0soft",
    "tags": null,
    "validationResult": {
      "summary": "OK"
    }
  },
  "modelOutput": {
    "shifts": [
      {
        "id": "Mon Day",
        "employee": "Ann"
      },
      {
        "id": "Mon Evening",
        "employee": "Beth"
      },
      {
        "id": "Tue Day",
        "employee": "Ann"
      },
      {
        "id": "Tue Evening",
        "employee": "Beth"
      }
    ]
  },
  "kpis": {
    "unassignedShifts": 0
  }
}

modelOutput contains the employee schedule with both Ann and Beth assigned to shifts that do not occur during their unpreferred times.

9. Filtering preferences with tags

Tags can be added to preferredTimeSpans and unpreferredTimeSpans to control which shifts the time spans apply to.

Tags can be used to specify preferences that apply to other aspects of employees' jobs. Employees might prefer to work at specific locations or in specific departments.

Shifts are assigned tags that can be matched against the available employees.

{
  "shifts": [
    {
      "id": "2027-02-01",
      "start": "2027-02-01T08:00:00Z",
      "end": "2027-02-01T16:00:00Z",
      "tags": [
        "department a"
      ]
    }
  ]
}

Ann prefers to work in Department A, so her preferredTimeSpan includes "includeShiftTags": [ "department a" ]:

{
  "id": "Ann",
  "preferredTimeSpans": [
    {
      "start": "2027-02-01T00:00:00Z",
      "end": "2027-02-03T00:00:00Z",
      "includeShiftTags": [
        "department a"
      ]
    }
  ]
}

In the following example, Ann prefers to work in Department A, and Beth prefers to work in Department B.

  • 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": "Preferences with tags example"
    }
  },
  "modelInput": {
    "employees": [
      {
        "id": "Ann",
        "preferredTimeSpans": [
          {
            "start": "2027-02-01T00:00:00Z",
            "end": "2027-02-03T00:00:00Z",
            "includeShiftTags": [
              "department a"
            ]
          }
        ]
      },
      {
        "id": "Beth",
        "preferredTimeSpans": [
          {
            "start": "2027-02-01T00:00:00Z",
            "end": "2027-02-03T00:00:00Z",
            "includeShiftTags": [
              "department b"
            ]
          }
        ]
      }
    ],
    "shifts": [
      {
        "id": "2027-02-01",
        "start": "2027-02-01T08:00:00Z",
        "end": "2027-02-01T16:00:00Z",
        "tags": [
          "department a"
        ]
      },
      {
        "id": "2027-02-02",
        "start": "2027-02-02T08:00:00Z",
        "end": "2027-02-02T16:00:00Z",
        "tags": [
          "department b"
        ]
      }
    ]
  }
}
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": "Preferences with tags example",
    "submitDateTime": "2024-09-24T04:46:48.692291772Z",
    "startDateTime": "2024-09-24T04:46:54.278513444Z",
    "activeDateTime": "2024-09-24T04:46:54.378513444Z",
    "completeDateTime": "2024-09-24T04:51:54.633244732Z",
    "shutdownDateTime": "2024-09-24T04:51:54.733244732Z",
    "solverStatus": "SOLVING_COMPLETED",
    "score": "0hard/0medium/1920soft",
    "tags": null,
    "validationResult": {
      "summary": "OK"
    }
  },
  "modelOutput": {
    "shifts": [
      {
        "id": "2027-02-01",
        "employee": "Ann"
      },
      {
        "id": "2027-02-02",
        "employee": "Beth"
      }
    ]
  },
  "kpis": {
    "unassignedShifts": 0
  }
}

modelOutput contains the employee schedule with both Ann and Beth assigned to shifts in their preferred departments.

If an employee prefers not work in a specific department, you can define this preference with excludeShiftTags:

{
  "id": "Ann",
  "preferredTimeSpans": [
    {
      "start": "2027-02-01T00:00:00Z",
      "end": "2027-02-03T00:00:00Z",
      "excludeShiftTags": [
        "department b"
      ]
    }
  ]
}

If shifts have multiple tags, you decide whether to match ALL or ANY of the tags based on employee preferences by including shiftTagMatches.

{
  "preferredTimeSpans": [
    {
      "start": "2027-02-01T00:00:00Z",
      "end": "2027-02-03T00:00:00Z",
      "includeShiftTags": [
        "department a",
        "location central"
      ],
      "shiftTagMatches": "ALL"
    }
  ]
}

With shiftTagMatches set to "ALL", a shift must include all the tags defined by the employee to match.

With shiftTagMatches set to "ANY", a shift must include at least one of the tags defined by the employee to match.

If shiftTagMatches is not included in the modelInput, all tags must match.

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.

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