# Nurse Scheduling

Consider a nurse scheduling problem for a department at a particular hospital.
Every day, there are three 12-hour shifts starting at 7hr, 13hr, 19hr. The
planning horizon is four days, starting on 2023-05-01, for a total of 12 shifts.
There are four registered nurses that can be assigned to these shifts, with the
goal of having two nurses in the department at any given time. The coverage
requirement is mandatory.

All nurses need to rest between shifts for at least 12 hours (720 minutes), and
can work at most 36 hours (2160 minutes) during the specified planning horizon.
These constraints have high and medium priority, respectively.

## Several shifts per day

Three shifts per day are represented as three independent shifts. For example,
shifts for the first day (out of four days) at the "department" location are
represented as:

      {
        "shifts": [{
          "id": "2023-05-01 7hr",
          "locationId": "department",
          "startDateTime": {
            "year": 2023,
            "month": 5,
            "day": 1,
            "hours": 7
          },
          "endDateTime": {
            "year": 2023,
            "month": 5,
            "day": 1,
            "hours": 19
          }
        }, {
          "id": "2023-05-01 13hr",
          "locationId": "department",
          "startDateTime": {
            "year": 2023,
            "month": 5,
            "day": 1,
            "hours": 13
          },
          "endDateTime": {
            "year": 2023,
            "month": 5,
            "day": 2,
            "hours": 1
          }
        }, {
          "id": "2023-05-01 19hr",
          "locationId": "department",
          "startDateTime": {
            "year": 2023,
            "month": 5,
            "day": 1,
            "hours": 19
          },
          "endDateTime": {
            "year": 2023,
            "month": 5,
            "day": 2,
            "hours": 7
          }
        },
        ...
        ]
      }

#### Example with 12 shifts (four days with three shifts per day)


        {
          "shifts": [{
          "id": "2023-05-01 7hr",
          "locationId": "department",
          "startDateTime": {
            "year": 2023,
            "month": 5,
            "day": 1,
            "hours": 7
          },
          "endDateTime": {
            "year": 2023,
            "month": 5,
            "day": 1,
            "hours": 19
          }
        }, {
          "id": "2023-05-01 13hr",
          "locationId": "department",
          "startDateTime": {
            "year": 2023,
            "month": 5,
            "day": 1,
            "hours": 13
          },
          "endDateTime": {
            "year": 2023,
            "month": 5,
            "day": 2,
            "hours": 1
          }
        }, {
          "id": "2023-05-01 19hr",
          "locationId": "department",
          "startDateTime": {
            "year": 2023,
            "month": 5,
            "day": 1,
            "hours": 19
          },
          "endDateTime": {
            "year": 2023,
            "month": 5,
            "day": 2,
            "hours": 7
          }
        }, {
          "id": "2023-05-02 7hr",
          "locationId": "department",
          "startDateTime": {
            "year": 2023,
            "month": 5,
            "day": 2,
            "hours": 7
          },
          "endDateTime": {
            "year": 2023,
            "month": 5,
            "day": 2,
            "hours": 19
          }
        }, {
          "id": "2023-05-02 13hr",
          "locationId": "department",
          "startDateTime": {
            "year": 2023,
            "month": 5,
            "day": 2,
            "hours": 13
          },
          "endDateTime": {
            "year": 2023,
            "month": 5,
            "day": 3,
            "hours": 1
          }
        }, {
          "id": "2023-05-02 19hr",
          "locationId": "department",
          "startDateTime": {
            "year": 2023,
            "month": 5,
            "day": 2,
            "hours": 19
          },
          "endDateTime": {
            "year": 2023,
            "month": 5,
            "day": 3,
            "hours": 7
          }
        }, {
          "id": "2023-05-03 7hr",
          "locationId": "department",
          "startDateTime": {
            "year": 2023,
            "month": 5,
            "day": 3,
            "hours": 7
          },
          "endDateTime": {
            "year": 2023,
            "month": 5,
            "day": 3,
            "hours": 19
          }
        }, {
          "id": "2023-05-03 13hr",
          "locationId": "department",
          "startDateTime": {
            "year": 2023,
            "month": 5,
            "day": 3,
            "hours": 13
          },
          "endDateTime": {
            "year": 2023,
            "month": 5,
            "day": 4,
            "hours": 1
          }
        }, {
          "id": "2023-05-03 19hr",
          "locationId": "department",
          "startDateTime": {
            "year": 2023,
            "month": 5,
            "day": 3,
            "hours": 19
          },
          "endDateTime": {
            "year": 2023,
            "month": 5,
            "day": 4,
            "hours": 7
          }
        }, {
          "id": "2023-05-04 7hr",
          "locationId": "department",
          "startDateTime": {
            "year": 2023,
            "month": 5,
            "day": 4,
            "hours": 7
          },
          "endDateTime": {
            "year": 2023,
            "month": 5,
            "day": 4,
            "hours": 19
          }
        }, {
          "id": "2023-05-04 13hr",
          "locationId": "department",
          "startDateTime": {
            "year": 2023,
            "month": 5,
            "day": 4,
            "hours": 13
          },
          "endDateTime": {
            "year": 2023,
            "month": 5,
            "day": 5,
            "hours": 1
          }
        }, {
          "id": "2023-05-04 19hr",
          "locationId": "department",
          "startDateTime": {
            "year": 2023,
            "month": 5,
            "day": 4,
            "hours": 19
          },
          "endDateTime": {
            "year": 2023,
            "month": 5,
            "day": 5,
            "hours": 7
          }
        }]
      }
      
## Rest between shifts

To represent the rest between shifts for an employee, use the
`minimumRestMinutes` field from a
[scheduling constraint](https://developers.google.com/optimization/service/reference/rest/v1/scheduling/solveShiftScheduling#schedulingconstraint). The start and end times of
the constraint are used to determine which shifts to consider, and therefore
should align with a planning horizon by overlapping with all the shifts. The
rest time is specified in minutes (720) and the priority is `PRIORITY_HIGH` as
stated above. The first nurse (called Adam), is represented as:

      {
        "employees": [{
          "id": "Adam",
          "roleIds": ["Registered Nurse"],
          "schedulingConstraints": [{
            "priority": "PRIORITY_HIGH",
            "startDateTime": {
              "year": 2023,
              "month": 5,
              "day": 1,
              "hours": 7
            },
            "endDateTime": {
              "year": 2023,
              "month": 5,
              "day": 5,
              "hours": 7
            },
            "minimumRestMinutes": 720
          }]
        }
      }

## Maximum working time

The maximum amount of time that an employee can work is also represented with a
[scheduling constraint](https://developers.google.com/optimization/service/reference/rest/v1/scheduling/solveShiftScheduling#schedulingconstraint), using the `maximumMinutes`
field. The maximum working time in this example is 2160 minutes. The start and
end times of the constraint should align with the entire planning horizon. The
corresponding representation for the first nurse (Adam) can be updated to:

      {
        "employees": [{
          "id": "Adam",
          "roleIds": ["Registered Nurse"],
          "schedulingConstraints": [{
            "priority": "PRIORITY_HIGH",
            "startDateTime": {
              "year": 2023,
              "month": 5,
              "day": 1,
              "hours": 7
            },
            "endDateTime": {
              "year": 2023,
              "month": 5,
              "day": 5,
              "hours": 7
            },
            "minimumRestMinutes": 720
          }, {
            "priority": "PRIORITY_MEDIUM",
            "startDateTime": {
              "year": 2023,
              "month": 5,
              "day": 1,
              "hours": 7
            },
            "endDateTime": {
              "year": 2023,
              "month": 5,
              "day": 5,
              "hours": 7
            },
            "maximumMinutes": 2160
          }]
        }
      }

#### Example with all four employees


      {
          "employees": [{
            "id": "Adam",
            "roleIds": ["Registered Nurse"],
            "schedulingConstraints": [{
              "priority": "PRIORITY_HIGH",
              "startDateTime": {
                "year": 2023,
                "month": 5,
                "day": 1,
                "hours": 7
              },
              "endDateTime": {
                "year": 2023,
                "month": 5,
                "day": 5,
                "hours": 7
              },
              "minimumRestMinutes": 720
            }, {
              "priority": "PRIORITY_MEDIUM",
              "startDateTime": {
                "year": 2023,
                "month": 5,
                "day": 1,
                "hours": 7
              },
              "endDateTime": {
                "year": 2023,
                "month": 5,
                "day": 5,
                "hours": 7
              },
              "maximumMinutes": 2160
            }]
          }, {
            "id": "Grace",
            "roleIds": ["Registered Nurse"],
            "schedulingConstraints": [{
              "priority": "PRIORITY_HIGH",
              "startDateTime": {
                "year": 2023,
                "month": 5,
                "day": 1,
                "hours": 7
              },
              "endDateTime": {
                "year": 2023,
                "month": 5,
                "day": 5,
                "hours": 7
              },
              "minimumRestMinutes": 720
            }, {
              "priority": "PRIORITY_MEDIUM",
              "startDateTime": {
                "year": 2023,
                "month": 5,
                "day": 1,
                "hours": 7
              },
              "endDateTime": {
                "year": 2023,
                "month": 5,
                "day": 5,
                "hours": 7
              },
              "maximumMinutes": 2160
            }]
          }, {
            "id": "James",
            "roleIds": ["Registered Nurse"],
            "schedulingConstraints": [{
              "priority": "PRIORITY_HIGH",
              "startDateTime": {
                "year": 2023,
                "month": 5,
                "day": 1,
                "hours": 7
              },
              "endDateTime": {
                "year": 2023,
                "month": 5,
                "day": 5,
                "hours": 7
              },
              "minimumRestMinutes": 720
            }, {
              "priority": "PRIORITY_MEDIUM",
              "startDateTime": {
                "year": 2023,
                "month": 5,
                "day": 1,
                "hours": 7
              },
              "endDateTime": {
                "year": 2023,
                "month": 5,
                "day": 5,
                "hours": 7
              },
              "maximumMinutes": 2160
            }]
          }, {
            "id": "Alonso",
            "roleIds": ["Registered Nurse"],
            "schedulingConstraints": [{
              "priority": "PRIORITY_HIGH",
              "startDateTime": {
                "year": 2023,
                "month": 5,
                "day": 1,
                "hours": 7
              },
              "endDateTime": {
                "year": 2023,
                "month": 5,
                "day": 5,
                "hours": 7
              },
              "minimumRestMinutes": 720
            }, {
              "priority": "PRIORITY_MEDIUM",
              "startDateTime": {
                "year": 2023,
                "month": 5,
                "day": 1,
                "hours": 7
              },
              "endDateTime": {
                "year": 2023,
                "month": 5,
                "day": 5,
                "hours": 7
              },
              "maximumMinutes": 2160
            }]
          }]
      }
      
## Coverage for registered nurses

Coverage of two registered nurses at any given moment is represented with a
[coverage requirement](https://developers.google.com/optimization/service/reference/rest/v1/scheduling/solveShiftScheduling#coveragerequirement). In particular,
`roleRequirements` is filled out with one
[role requirement](https://developers.google.com/optimization/service/reference/rest/v1/scheduling/solveShiftScheduling#rolerequirement) for which the `roleId` is set to
"Registered Nurse", `targetEmployeeCount` is set to 2, and `priority` is set to
`PRIORITY_MANDATORY`. The start and end times of the coverage requirement should
overlap with every shift. The `locationId` field is set to "department" so that
only shifts happening in this location are considered.

      {
        "coverageRequirements": [{
          "startDateTime": {
            "year": 2023,
            "month": 5,
            "day": 1,
            "hours": 7
          },
          "endDateTime": {
            "year": 2023,
            "month": 5,
            "day": 5,
            "hours": 7
          },
          "locationId": "department",
          "roleRequirements": [{
            "roleId": "Registered Nurse",
            "targetEmployeeCount": 2,
            "priority": "PRIORITY_MANDATORY"
          }]
        }],
        "roleIds": ["Registered Nurse"],
        "locationIds": ["department"]
      }

#### Example of a complete request


        {
          "employees": [{
            "id": "Adam",
            "roleIds": ["Registered Nurse"],
            "schedulingConstraints": [{
              "priority": "PRIORITY_HIGH",
              "startDateTime": {
                "year": 2023,
                "month": 5,
                "day": 1,
                "hours": 7
              },
              "endDateTime": {
                "year": 2023,
                "month": 5,
                "day": 5,
                "hours": 7
              },
              "minimumRestMinutes": 720
            }, {
              "priority": "PRIORITY_MEDIUM",
              "startDateTime": {
                "year": 2023,
                "month": 5,
                "day": 1,
                "hours": 7
              },
              "endDateTime": {
                "year": 2023,
                "month": 5,
                "day": 5,
                "hours": 7
              },
              "maximumMinutes": 2160
            }]
          }, {
            "id": "Grace",
            "roleIds": ["Registered Nurse"],
            "schedulingConstraints": [{
              "priority": "PRIORITY_HIGH",
              "startDateTime": {
                "year": 2023,
                "month": 5,
                "day": 1,
                "hours": 7
              },
              "endDateTime": {
                "year": 2023,
                "month": 5,
                "day": 5,
                "hours": 7
              },
              "minimumRestMinutes": 720
            }, {
              "priority": "PRIORITY_MEDIUM",
              "startDateTime": {
                "year": 2023,
                "month": 5,
                "day": 1,
                "hours": 7
              },
              "endDateTime": {
                "year": 2023,
                "month": 5,
                "day": 5,
                "hours": 7
              },
              "maximumMinutes": 2160
            }]
          }, {
            "id": "James",
            "roleIds": ["Registered Nurse"],
            "schedulingConstraints": [{
              "priority": "PRIORITY_HIGH",
              "startDateTime": {
                "year": 2023,
                "month": 5,
                "day": 1,
                "hours": 7
              },
              "endDateTime": {
                "year": 2023,
                "month": 5,
                "day": 5,
                "hours": 7
              },
              "minimumRestMinutes": 720
            }, {
              "priority": "PRIORITY_MEDIUM",
              "startDateTime": {
                "year": 2023,
                "month": 5,
                "day": 1,
                "hours": 7
              },
              "endDateTime": {
                "year": 2023,
                "month": 5,
                "day": 5,
                "hours": 7
              },
              "maximumMinutes": 2160
            }]
          }, {
            "id": "Alonso",
            "roleIds": ["Registered Nurse"],
            "schedulingConstraints": [{
              "priority": "PRIORITY_HIGH",
              "startDateTime": {
                "year": 2023,
                "month": 5,
                "day": 1,
                "hours": 7
              },
              "endDateTime": {
                "year": 2023,
                "month": 5,
                "day": 5,
                "hours": 7
              },
              "minimumRestMinutes": 720
            }, {
              "priority": "PRIORITY_MEDIUM",
              "startDateTime": {
                "year": 2023,
                "month": 5,
                "day": 1,
                "hours": 7
              },
              "endDateTime": {
                "year": 2023,
                "month": 5,
                "day": 5,
                "hours": 7
              },
              "maximumMinutes": 2160
            }]
          }],
          "shifts": [{
            "id": "2023-05-01 7hr",
            "locationId": "department",
            "startDateTime": {
              "year": 2023,
              "month": 5,
              "day": 1,
              "hours": 7
            },
            "endDateTime": {
              "year": 2023,
              "month": 5,
              "day": 1,
              "hours": 19
            }
          }, {
            "id": "2023-05-01 13hr",
            "locationId": "department",
            "startDateTime": {
              "year": 2023,
              "month": 5,
              "day": 1,
              "hours": 13
            },
            "endDateTime": {
              "year": 2023,
              "month": 5,
              "day": 2,
              "hours": 1
            }
          }, {
            "id": "2023-05-01 19hr",
            "locationId": "department",
            "startDateTime": {
              "year": 2023,
              "month": 5,
              "day": 1,
              "hours": 19
            },
            "endDateTime": {
              "year": 2023,
              "month": 5,
              "day": 2,
              "hours": 7
            }
          }, {
            "id": "2023-05-02 7hr",
            "locationId": "department",
            "startDateTime": {
              "year": 2023,
              "month": 5,
              "day": 2,
              "hours": 7
            },
            "endDateTime": {
              "year": 2023,
              "month": 5,
              "day": 2,
              "hours": 19
            }
          }, {
            "id": "2023-05-02 13hr",
            "locationId": "department",
            "startDateTime": {
              "year": 2023,
              "month": 5,
              "day": 2,
              "hours": 13
            },
            "endDateTime": {
              "year": 2023,
              "month": 5,
              "day": 3,
              "hours": 1
            }
          }, {
            "id": "2023-05-02 19hr",
            "locationId": "department",
            "startDateTime": {
              "year": 2023,
              "month": 5,
              "day": 2,
              "hours": 19
            },
            "endDateTime": {
              "year": 2023,
              "month": 5,
              "day": 3,
              "hours": 7
            }
          }, {
            "id": "2023-05-03 7hr",
            "locationId": "department",
            "startDateTime": {
              "year": 2023,
              "month": 5,
              "day": 3,
              "hours": 7
            },
            "endDateTime": {
              "year": 2023,
              "month": 5,
              "day": 3,
              "hours": 19
            }
          }, {
            "id": "2023-05-03 13hr",
            "locationId": "department",
            "startDateTime": {
              "year": 2023,
              "month": 5,
              "day": 3,
              "hours": 13
            },
            "endDateTime": {
              "year": 2023,
              "month": 5,
              "day": 4,
              "hours": 1
            }
          }, {
            "id": "2023-05-03 19hr",
            "locationId": "department",
            "startDateTime": {
              "year": 2023,
              "month": 5,
              "day": 3,
              "hours": 19
            },
            "endDateTime": {
              "year": 2023,
              "month": 5,
              "day": 4,
              "hours": 7
            }
          }, {
            "id": "2023-05-04 7hr",
            "locationId": "department",
            "startDateTime": {
              "year": 2023,
              "month": 5,
              "day": 4,
              "hours": 7
            },
            "endDateTime": {
              "year": 2023,
              "month": 5,
              "day": 4,
              "hours": 19
            }
          }, {
            "id": "2023-05-04 13hr",
            "locationId": "department",
            "startDateTime": {
              "year": 2023,
              "month": 5,
              "day": 4,
              "hours": 13
            },
            "endDateTime": {
              "year": 2023,
              "month": 5,
              "day": 5,
              "hours": 1
            }
          }, {
            "id": "2023-05-04 19hr",
            "locationId": "department",
            "startDateTime": {
              "year": 2023,
              "month": 5,
              "day": 4,
              "hours": 19
            },
            "endDateTime": {
              "year": 2023,
              "month": 5,
              "day": 5,
              "hours": 7
            }
          }],
          "coverageRequirements": [{
            "startDateTime": {
              "year": 2023,
              "month": 5,
              "day": 1,
              "hours": 7
            },
            "endDateTime": {
              "year": 2023,
              "month": 5,
              "day": 5,
              "hours": 7
            },
            "locationId": "department",
            "roleRequirements": [{
              "roleId": "Registered Nurse",
              "targetEmployeeCount": 2,
              "priority": "PRIORITY_MANDATORY"
            }]
          }],
          "roleIds": ["Registered Nurse"],
          "locationIds": ["department"]
        }
        
## Response example

The response of the solver contains the assignment of nurses to shifts and the
status of the optimization procedure. For example, the shifts assigned to the
first employee are returned as:

      {
        "solutionStatus": "OPTIMAL",
        "shiftAssignments": [
          {
            "employeeId": "Adam",
            "shiftId": "2023-05-01 7hr",
            "roleId": "Registered Nurse"
          },
          {
            "employeeId": "Adam",
            "shiftId": "2023-05-02 7hr",
            "roleId": "Registered Nurse"
          },
          {
            "employeeId": "Adam",
            "shiftId": "2023-05-03 7hr",
            "roleId": "Registered Nurse"
          },
          {
            "employeeId": "Adam",
            "shiftId": "2023-05-04 7hr",
            "roleId": "Registered Nurse"
          },
          ... ]
      }

#### Example of a complete response


        {
          "solutionStatus": "OPTIMAL",
          "shiftAssignments": [
            {
              "employeeId": "Adam",
              "shiftId": "2023-05-01 7hr",
              "roleId": "Registered Nurse"
            },
            {
              "employeeId": "Adam",
              "shiftId": "2023-05-02 7hr",
              "roleId": "Registered Nurse"
            },
            {
              "employeeId": "Adam",
              "shiftId": "2023-05-03 7hr",
              "roleId": "Registered Nurse"
            },
            {
              "employeeId": "Adam",
              "shiftId": "2023-05-04 7hr",
              "roleId": "Registered Nurse"
            },
            {
              "employeeId": "Grace",
              "shiftId": "2023-05-01 19hr",
              "roleId": "Registered Nurse"
            },
            {
              "employeeId": "Grace",
              "shiftId": "2023-05-02 19hr",
              "roleId": "Registered Nurse"
            },
            {
              "employeeId": "Grace",
              "shiftId": "2023-05-03 19hr",
              "roleId": "Registered Nurse"
            },
            {
              "employeeId": "Grace",
              "shiftId": "2023-05-04 19hr",
              "roleId": "Registered Nurse"
            },
            {
              "employeeId": "James",
              "shiftId": "2023-05-01 19hr",
              "roleId": "Registered Nurse"
            },
            {
              "employeeId": "James",
              "shiftId": "2023-05-02 19hr",
              "roleId": "Registered Nurse"
            },
            {
              "employeeId": "James",
              "shiftId": "2023-05-03 19hr",
              "roleId": "Registered Nurse"
            },
            {
              "employeeId": "James",
              "shiftId": "2023-05-04 19hr",
              "roleId": "Registered Nurse"
            },
            {
              "employeeId": "Alonso",
              "shiftId": "2023-05-01 7hr",
              "roleId": "Registered Nurse"
            },
            {
              "employeeId": "Alonso",
              "shiftId": "2023-05-02 7hr",
              "roleId": "Registered Nurse"
            },
            {
              "employeeId": "Alonso",
              "shiftId": "2023-05-03 7hr",
              "roleId": "Registered Nurse"
            },
            {
              "employeeId": "Alonso",
              "shiftId": "2023-05-04 7hr",
              "roleId": "Registered Nurse"
            }
          ]
        }