> ## Documentation Index
> Fetch the complete documentation index at: https://docs.automaticrostering.visma.net/llms.txt
> Use this file to discover all available pages before exploring further.

# Period Distribution

> Set rules for how many periods (marked by labels) an employee can work.

export const PeriodDistributionMetricRows = () => <>
    <tr><td><code className="whitespace-nowrap">PERIOD_DISTRIBUTION.WORKED_PERIODS</code></td><td>Number of periods with at least one assignment.</td></tr>
    <tr><td><code className="whitespace-nowrap">PERIOD_DISTRIBUTION.MISSING_WORKED_PERIODS</code></td><td>Total number of required worked periods that are missing.</td></tr>
    <tr><td><code className="whitespace-nowrap">PERIOD_DISTRIBUTION.EXCESSIVE_WORKED_PERIODS</code></td><td>Total number of worked periods above configured maximums.</td></tr>
    <tr><td><code className="whitespace-nowrap">PERIOD_DISTRIBUTION.MAX_CONSECUTIVE_VIOLATIONS</code></td><td>Total amount by which consecutive worked-period groups exceed their maximum.</td></tr>
    <tr><td><code className="whitespace-nowrap">PERIOD_DISTRIBUTION.MIN_SURROUNDING_VIOLATIONS</code></td><td>Total number of required surrounding free periods that are missing.</td></tr>
  </>;

Define rules to improve the distribution of inconvenient periods among employees.

<Card title="Rule schema">
  <ResponseField name="periodDistributionRule" type="object">
    Used to define targets and limits for the distribution of periods (like weekends, holidays, nights).

    <Expandable title="properties">
      <ResponseField name="id" type="string" required>
        Unique identifier for the rule.
      </ResponseField>

      <ResponseField name="labels" type="array of string">
        Labels for the rule. Labels can be used to group rules together. For example, if multiple rules are related to the same shift type, they can all be labeled with the same label.
      </ResponseField>

      <ResponseField name="importance" type="string (enum: NONE | VERY_LOW | LOW | MEDIUM | HIGH | ...)" required>
        The importance of the rule. The higher the importance, the more it will be taking the rule into account. Under strict importance, the rule may never be violated.
      </ResponseField>

      <ResponseField name="filters" type="object">
        Filters to determine the scope of the rule. Used to indicate what the rule should be applied to (which employees, which shifts, etc). Leaving this empty means that the rule always applies.
      </ResponseField>

      <Expandable title="filters – properties">
        <ResponseField name="employees" type="object">
          Used to filter which employees the rule should be applied to. If not specified, the rule applies to all employees.
        </ResponseField>

        <Expandable title="employees – properties">
          <ResponseField name="ids" type="array of string">
            List of employee ids that the rule should be applied to.
          </ResponseField>

          <ResponseField name="labels" type="array of string">
            List of employee labels that the rule should be applied to.
          </ResponseField>

          <ResponseField name="matchTypes" type="object" />

          <Expandable title="matchTypes – properties">
            <ResponseField name="ids" type="string (enum: NONE | ANY | ALL)">
              Used to indicate how to apply the id filters. For example, if set to NONE, entities with the specified ids will be excluded. Default: "ANY".
            </ResponseField>

            <ResponseField name="labels" type="string (enum: NONE | ANY | ALL)">
              Used to indicate how to apply the label filters. For example, if set to ANY, entities that have any of the specified labels will be included. Default: "ANY".
            </ResponseField>
          </Expandable>
        </Expandable>

        <ResponseField name="shifts" type="object">
          Used to filter which shifts the rule should be applied to. If not specified, the rule applies to all shifts.
        </ResponseField>

        <Expandable title="shifts – properties">
          <ResponseField name="ids" type="array of string">
            List of shift ids that the rule should be applied to.
          </ResponseField>

          <ResponseField name="labels" type="array of string">
            List of shift labels that the rule should be applied to.
          </ResponseField>

          <ResponseField name="matchTypes" type="object" />

          <Expandable title="matchTypes – properties">
            <ResponseField name="ids" type="string (enum: NONE | ANY | ALL)">
              Used to indicate how to apply the id filters. For example, if set to NONE, entities with the specified ids will be excluded. Default: "ANY".
            </ResponseField>

            <ResponseField name="labels" type="string (enum: NONE | ANY | ALL)">
              Used to indicate how to apply the label filters. For example, if set to ANY, entities that have any of the specified labels will be included. Default: "ANY".
            </ResponseField>
          </Expandable>
        </Expandable>
      </Expandable>

      <ResponseField name="targets" type="object" required>
        Defines targets and limits on the distribution of worked periods.
      </ResponseField>

      <Expandable title="targets – properties">
        <ResponseField name="minWorkedPeriods" type="integer">
          The minimum amount of periods in which the employee should work. This is treated as a target instead of a strict limit.
        </ResponseField>

        <ResponseField name="maxWorkedPeriods" type="integer">
          The maximum amount of periods in which the employee can work.
        </ResponseField>

        <ResponseField name="maxConsecutiveWorkedPeriods" type="integer">
          The maximum amount of consecutive periods in which the employee can work.
        </ResponseField>

        <ResponseField name="minSurroundingFreePeriods" type="integer">
          The minimum amount of non-worked periods both before and after a worked period.
        </ResponseField>
      </Expandable>

      <ResponseField name="options" type="object">
        Additional options for how the rule should be applied.
      </ResponseField>

      <Expandable title="options – properties">
        <ResponseField name="overlapSettings" type="object">
          Specifies overlap thresholds that a shift must meet with the rule's periods in order for it to be counted as relevant for the rule.
        </ResponseField>

        <Expandable title="overlapSettings – properties">
          <ResponseField name="minOverlapHours" type="integer">
            The minimum number of hours that a shift must overlap with the rule in order to be counted as relevant for this rule.
          </ResponseField>

          <ResponseField name="minOverlapPercentage" type="integer">
            The minimum percentage of the shift that must overlap with the rule in order to be counted as relevant for this rule.
          </ResponseField>
        </Expandable>
      </Expandable>

      <ResponseField name="periods" type="object">
        List of periods in the schedule. Periods can be defined explicitly or through a recurrent definition (for example, to generate weeks).
      </ResponseField>

      <Expandable title="periods – properties">
        <ResponseField name="days" type="object">
          List of days in the schedule. Each day will become one period. By default, each period will last the entire day. If a startTime and/or endTime are specified, these will apply to each period.
        </ResponseField>

        <Expandable title="days – properties">
          <ResponseField name="dates" type="array of date (date)">
            List of dates in the schedule. Only allowed in CALENDAR payloads.
          </ResponseField>

          <ResponseField name="dayIndices" type="array of dayIndex">
            List of day indices in the schedule. Only allowed in RECURRING payloads.
          </ResponseField>

          <ResponseField name="daysOfWeek" type="array of dayOfWeek">
            List of days of the week. Will apply to all days in the schedule that match any of the specified weekdays.
          </ResponseField>

          <ResponseField name="startTime" type="string (time)">
            TIME ISO 8601 format hh:mm. Equivalent to the 24h format of a single day. Use 00:00 to represent midnight.
          </ResponseField>

          <ResponseField name="endTime" type="string (time)">
            TIME ISO 8601 format hh:mm. Equivalent to the 24h format of a single day. Use 00:00 to represent midnight.
          </ResponseField>
        </Expandable>

        <ResponseField name="customDefinitions" type="array of object">
          List of custom period definitions. Each custom period definition defines one period in the schedule.
        </ResponseField>

        <Expandable title="customDefinitions – item structure">
          <ResponseField name="startDay" type="object">
            Describes one day in the schedule.
          </ResponseField>

          <Expandable title="startDay – properties">
            <ResponseField name="date" type="string (date)">
              Date specified in ISO8601 format (YYYY-MM-DD). Only available in CALENDAR schedules.
            </ResponseField>

            <ResponseField name="dayIndex" type="integer">
              Day index relative to the horizon start day (starts at 0). Only available in RECURRING schedules.
            </ResponseField>
          </Expandable>

          <ResponseField name="endDay" type="object">
            Describes one day in the schedule.
          </ResponseField>

          <Expandable title="endDay – properties">
            <ResponseField name="date" type="string (date)">
              Date specified in ISO8601 format (YYYY-MM-DD). Only available in CALENDAR schedules.
            </ResponseField>

            <ResponseField name="dayIndex" type="integer">
              Day index relative to the horizon start day (starts at 0). Only available in RECURRING schedules.
            </ResponseField>
          </Expandable>

          <ResponseField name="startTime" type="string (time)">
            TIME ISO 8601 format hh:mm. Equivalent to the 24h format of a single day. Use 00:00 to represent midnight.
          </ResponseField>

          <ResponseField name="endTime" type="string (time)">
            TIME ISO 8601 format hh:mm. Equivalent to the 24h format of a single day. Use 00:00 to represent midnight.
          </ResponseField>

          <ResponseField name="applyTimeToAllDays" type="boolean">
            If true, the startTime and endTime will be applied to each individual day in the period. If false, the startTime will apply to the first day and the endTime will apply to the last day. Default: false.
          </ResponseField>
        </Expandable>

        <ResponseField name="recurrentDefinition" type="object">
          A recurrent definition to easily create a set of similar periods.
        </ResponseField>

        <Expandable title="recurrentDefinition – properties">
          <ResponseField name="daysPerPeriod" type="integer" required>
            The number of days in each period.
          </ResponseField>

          <ResponseField name="daysBetweenStarts" type="integer">
            The number of days between the start of each period. If not specified, this defaults to the value of daysPerPeriod, creating non-overlapping consecutive periods. Setting daysBetweenStarts to 1 will create a sliding window of periods.
          </ResponseField>

          <ResponseField name="startDay" type="object">
            Describes one day in the schedule.
          </ResponseField>

          <Expandable title="startDay – properties">
            <ResponseField name="date" type="string (date)">
              Date specified in ISO8601 format (YYYY-MM-DD). Only available in CALENDAR schedules.
            </ResponseField>

            <ResponseField name="dayIndex" type="integer">
              Day index relative to the horizon start day (starts at 0). Only available in RECURRING schedules.
            </ResponseField>
          </Expandable>

          <ResponseField name="endDay" type="object">
            Describes one day in the schedule.
          </ResponseField>

          <Expandable title="endDay – properties">
            <ResponseField name="date" type="string (date)">
              Date specified in ISO8601 format (YYYY-MM-DD). Only available in CALENDAR schedules.
            </ResponseField>

            <ResponseField name="dayIndex" type="integer">
              Day index relative to the horizon start day (starts at 0). Only available in RECURRING schedules.
            </ResponseField>
          </Expandable>

          <ResponseField name="startTime" type="string (time)">
            TIME ISO 8601 format hh:mm. Equivalent to the 24h format of a single day. Use 00:00 to represent midnight.
          </ResponseField>

          <ResponseField name="endTime" type="string (time)">
            TIME ISO 8601 format hh:mm. Equivalent to the 24h format of a single day. Use 00:00 to represent midnight.
          </ResponseField>

          <ResponseField name="applyTimeToAllDays" type="boolean">
            If true, the startTime and endTime will be applied to each individual day in the period. If false, the startTime will apply to the first day and the endTime will apply to the last day. Default: false.
          </ResponseField>
        </Expandable>

        <ResponseField name="labels" type="array of string">
          Provide labels to re-use periods that were defined in the configuration.
        </ResponseField>
      </Expandable>
    </Expandable>
  </ResponseField>
</Card>

## Explanation

Within the context of this rule, a period is considered 'worked' for an employee if they work any shift during that period, and
'free' if they do not. The rule allows you to set targets for how many periods an employee can work, how many they can work in succession,
and how many free periods they must have surrounding a working period.

Often seen use cases are the distribution of weekends, holidays, or other inconvenient periods among employees.

## Maximum worked periods

An easy use case is to limit how many worked periods an employee can have.

<Tip>
  The rule below makes it undesirable for employees to work more than 2 weekends. Notice that working a shift is only considered
  as working a period if it overlaps for at least 6 hours with the period, as configured in `options.overlapSettings`.

  To work with `labels` on periods, make sure you have defined the period label in the `extensions.labeling` part of the payload.

  ```json theme={null}
  {
    "id": "pd-max-weekends",
    "importance": "MEDIUM",
    "targets": {
      "maxWorkedPeriods": 2
    },
    "options": {
      "overlapSettings": {
        "minOverlapHours": 6
      }
    },
    "periods": {
      "labels": ["WEEKENDS"]
    }
  }
  ```
</Tip>

## Minimum worked periods

Alternatively, the rule can be used to encourage a minimum amount of worked periods for an employee.

<Tip>
  The rule below sets a target for the minimum number of weekends during which the employee works any shift.
  `minWorkedPeriods` is never treated as a strict lower bound, but rather as a target that the solver will try to reach.

  ```json theme={null}
  {
    "id": "pd-min-weekends",
    "targets": {
      "minWorkedPeriods": 3
    },
    "periods": {
      "labels": ["WEEKENDS"]
    }
  }
  ```
</Tip>

## Maximum consecutive worked periods

Alternatively, the rule can be used to limit how many undesirable periods an employee can work in succession.

<Tip>
  The rule below makes it strictly forbidden for an employee to work 3 holidays in a row. Notice that with the way periods are defined,
  working both days of Christmas still only counts as working **one** period. If the days of Christmas should count as working separate holidays,
  you would need to define them as separate periods.

  ```json theme={null}
  {
    "id": "pd-max-consecutive-holidays",
    "importance": "STRICT",
    "targets": {
      "maxConsecutiveWorkedPeriods": 2
    },
    "periods": {
      "customDefinitions": [
        {
          "startDay": {
            "date": "2024-12-25"
          },
          "endDay": {
            "date": "2024-12-26"
          }
        },
        {
          "startDay": {
            "date": "2024-12-31"
          },
          "endDay": {
            "date": "2024-12-31"
          }
        }
      ]
    }
  }
  ```
</Tip>

## Minimum surrounding free periods

The rule can also be used to enforce a minimum number of free periods surrounding a worked period.

Note that it is currently not supported to use the `minSurroundingFreePeriods` property in combination with the `maxConsecutiveWorkedPeriods` property.

<Tip>
  The rule below makes it strictly required for an employee to have at least 1 free weekend surrounding each worked weekend.

  ```json theme={null}
  {
    "id": "pd-min-surrounding-free-weekends",
    "importance": "STRICT",
    "targets": {
      "minSurroundingFreePeriods": 1
    },
    "periods": {
      "labels": ["WEEKENDS"]
    }
  }
  ```
</Tip>

## Metrics

The following [status metrics](/v2/concepts/metrics) are available for tracking on Period Distribution rules:

<table>
  <thead><tr><th>Metric key</th><th>Description</th></tr></thead>

  <tbody>
    <PeriodDistributionMetricRows />
  </tbody>
</table>
