Employee preferences

Allowing employees to work during their preferred shifts can make a difference to employees' job satisfaction and performance at work.

For instance, employees might prefer to work certain shifts, at certain locations, or to perform certain roles.

Unless specified otherwise as part of an employee’s availability, employees are considered to be available for any shift. However, to optimize for employee satisfaction, any employee shift scheduling solution should take employee preferences into consideration.

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

Prerequisites

To run the examples in this guide, you need to authenticate with a valid API key:

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

  2. From the Dashboard, click your username, and from the drop-down menu select API Keys.

  3. Copy the default API key.

In the examples, replace <API_KEY> with the API Key you just copied.

The times displayed in the visualizations are approximates only.

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.

1. 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": "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 example",
    "submitDateTime": "2024-09-19T06:23:13.430778281Z",
    "startDateTime": "2024-09-19T06:23:18.972386292Z",
    "completeDateTime": "2024-09-19T06:28:19.350143099Z",
    "solverStatus": "SOLVING_COMPLETED",
    "score": "0hard/0medium/3840soft",
    "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 with both Ann and Beth assigned to shifts during their preferred times.

2. 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",
    "completeDateTime": "2024-09-19T07:12:22.013369565Z",
    "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.

3. 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": "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": "Unpreferred time spans example",
    "submitDateTime": "2024-09-20T06:56:27.642773329Z",
    "startDateTime": "2024-09-20T06:56:33.281870696Z",
    "completeDateTime": "2024-09-20T07:01:33.635593953Z",
    "solverStatus": "SOLVING_COMPLETED",
    "score": "0hard/0medium/0soft",
    "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 with both Ann and Beth assigned to shifts that do not occur during their unpreferred times.

4. 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",
    "completeDateTime": "2024-09-24T04:51:54.633244732Z",
    "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