{"id":23540993,"url":"https://github.com/point85/shift","last_synced_at":"2025-04-23T19:16:25.872Z","repository":{"id":56265282,"uuid":"75444339","full_name":"point85/Shift","owner":"point85","description":"The Shift library project manages work schedules with teams and shift rotations.","archived":false,"fork":false,"pushed_at":"2024-12-14T18:14:46.000Z","size":1708,"stargazers_count":20,"open_issues_count":0,"forks_count":8,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-04-23T19:16:13.098Z","etag":null,"topics":["java","shift","shift-calendar","work-calendar","work-schedule"],"latest_commit_sha":null,"homepage":"https://point85.github.io/work/","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/point85.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-12-03T01:35:18.000Z","updated_at":"2025-02-03T19:23:10.000Z","dependencies_parsed_at":"2024-02-06T18:45:55.586Z","dependency_job_id":"021cfa87-a218-4616-a76d-f3dc1fb99fb1","html_url":"https://github.com/point85/Shift","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/point85%2FShift","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/point85%2FShift/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/point85%2FShift/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/point85%2FShift/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/point85","download_url":"https://codeload.github.com/point85/Shift/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250496993,"owners_count":21440231,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["java","shift","shift-calendar","work-calendar","work-schedule"],"created_at":"2024-12-26T05:13:29.447Z","updated_at":"2025-04-23T19:16:25.840Z","avatar_url":"https://github.com/point85.png","language":"Java","readme":"# Shift\nThe Shift library project manages work schedules.  A work schedule consists of one or more teams who rotate through a sequence of shift and off-shift periods of time.  The Shift project allows breaks during shifts to be defined as well as non-working periods of time (e.g. holidays and scheduled maintenance periods) that are applicable to the entire work schedule.  This Java library is used in an OEE project that can be found at https://github.com/point85/OEE-Designer.  The Shift library is also available in C# at https://github.com/point85/ShiftSharp and in Python at https://github.com/point85/PyShift.\n\n## Concepts\n\nThe diagram below illustrates Business Management Systems' DNO (Day, Night, Off) work schedule with three teams and two 12-hour shifts with a 3-day rotation.  This schedule is explained in http://community.bmscentral.com/learnss/ZC/3T/c3tr12-1.\n\n![Work Schedule Diagram](https://github.com/point85/shift/blob/master/doc/DNO.png)\n\n*Shift*\n\nA shift is defined with a name, description, starting time of day and duration.  An off-shift period is associated with a shift.  In the example above for Team1, there are two shifts followed by one off-shift period.  Shifts can be overlapped (typically when a handoff of duties is important such as in the nursing profession).  A rotation is a sequence of shifts and off-shift days.  The DNO rotation is Day on, Night on and Night off.  An instance of a shift has a starting date and time of day and has an associated shift definition.\n\n*Break*\n\nA break is a defined working period of time during a shift, for example lunch.  A shift can have zero or more breaks.\n\n*Team*\n\nA team is defined with a name and description.  It has a rotation with a starting date.  The starting date shift will have an instance with that date and a starting time of day as defined by the shift.  The same rotation can be shared between more than one team, but with different starting times.\n\n*Team Member*\n\nA team member is a person assigned to a team.  The member is identified by a member ID (e.g. employee ID), name and description/title.\n\n*Team Member Exception*\n\nA team member exception is an addition and/or removal from the assigned members of a team for a specified shift instance.  The instance is identified by the starting date and time.\n\n*Work Schedule*\n\nA work schedule is defined with a name and description.  It has one or more teams.  Zero or more non-working periods can be defined.  A non-working period has a defined starting date and time of day and duration.  For example, the New Year's Day holiday starting at midnight for 24 hours, or three consecutive days for preventive maintenance of manufacturing equipment starting at the end of the night shift. \n\nAfter a work schedule is defined, the working time for all shifts can be computed for a defined time interval.  For example, this duration of time is the maximum available productive time as an input to the calculation of the utilization of equipment in a metric known as the Overall Equipment Effectiveness (OEE).\n\n*Rotation*\n\nA rotation is a sequence of working periods (segments).  Each segment starts with a shift and specifies the number of days on-shift and off-shift.  A work schedule can have more than one rotation.\n\n*Non-Working Period*\n\nA non-working period is a duration of time where no teams are working.  For example, a holiday or a period of time when a plant is shutdown for preventative maintenance.  A non-working period starts at a defined day and time of day and continues for the specified duration of time.\n\n*Shift Instance*\n\nA shift instance is the duration of time from a specified date and time of day and continues for the duration of the associated shift.  A team works this shift instance.\n\n## Examples\nThe DNO schedule discussed above is defined as follows.\n\n```java\nString description = \"This is a fast rotation plan that uses 3 teams and two 12-hr shifts to provide 24/7 coverage. \"\n\t\t+ \"Each team rotates through the following sequence every three days: 1 day shift, 1 night shift, and 1 day off.\";\n\nWorkSchedule schedule = new WorkSchedule(\"DNO Plan\", description);\n\n// Day shift, starts at 07:00 for 12 hours\nShift day = schedule.createShift(\"Day\", \"Day shift\", LocalTime.of(7, 0, 0), Duration.ofHours(12));\n\n// Night shift, starts at 19:00 for 12 hours\nShift night = schedule.createShift(\"Night\", \"Night shift\", LocalTime.of(19, 0, 0), Duration.ofHours(12));\n\n// rotation\nRotation rotation = new Rotation(\"DNO\", \"DNO\");\nrotation.addSegment(day, 1, 0);\nrotation.addSegment(night, 1, 1);\n\nschedule.createTeam(\"Team 1\", \"First team\", rotation, referenceDate);\nschedule.createTeam(\"Team 2\", \"Second team\", rotation, referenceDate.minusDays(1));\nschedule.createTeam(\"Team 3\", \"Third team\", rotation, referenceDate.minusDays(2));\n```\nTo obtain the working time over three days starting at 07:00, the following methods are called:\n\n```java\nLocalDateTime from = LocalDateTime.of(referenceDate, LocalTime.of(7, 0, 0));\nDuration duration = schedule.calculateWorkingTime(from, from.plusDays(3));\n```\n\nTo obtain the shift instances for a date, the following method is called:\n\n```java\nList\u003cShiftInstance\u003e instances = schedule.getShiftInstancesForDay(LocalDate.of(2017, 3, 1)); \n```\n\nTo print a work schedule, call the toString() method.  For example:\n\n```java\nSchedule: DNO Plan (This is a fast rotation plan that uses 3 teams and two 12-hr shifts to provide 24/7 coverage. Each team rotates through the following sequence every three days: 1 day shift, 1 night shift, and 1 day off.)\nRotation duration: PT216H, Scheduled working time: PT72H\nShifts: \n   (1) Day (Day shift), Start : 07:00 (PT12H), End : 19:00\n   (2) Night (Night shift), Start : 19:00 (PT12H), End : 07:00\nTeams: \n   (1) Team 1 (First team), Rotation start: 2016-10-31, Rotation periods: [Day (on), Night (on), (off) ], Rotation duration: PT72H, Days in rotation: 3, Scheduled working time: PT24H, Percentage worked: 33.33%, Average hours worked per week: PT56H\n   (2) Team 2 (Second team), Rotation start: 2016-10-30, Rotation periods: [Day (on), Night (on),(off) ], Rotation duration: PT72H, Days in rotation: 3, Scheduled working time: PT24H, Percentage worked: 33.33%, Average hours worked per week: PT56H\n   (3) Team 3 (Third team), Rotation start: 2016-10-29, Rotation periods: [Day (on), Night (on), (off) ], Rotation duration: PT72H, Days in rotation: 3, Scheduled working time: PT24H, Percentage worked: 33.33%, Average hours worked per week: PT56H\nTotal team coverage: 100%\n```\n\nTo print shift instances between two dates, the following method is called:\n\n ```java\nschedule.printShiftInstances(LocalDate.of(2016, 10, 31), LocalDate.of(2016, 11, 3)));\n```\nwith output:\n\n```java\nWorking shifts\n[1] Day: 2016-10-31\n   (1) Team: Team 1, Shift: Day, Start : 2016-10-31T07:00, End : 2016-10-31T19:00\n   (2) Team: Team 2, Shift: Night, Start : 2016-10-31T19:00, End : 2016-11-01T07:00\n[2] Day: 2016-11-01\n   (1) Team: Team 3, Shift: Day, Start : 2016-11-01T07:00, End : 2016-11-01T19:00\n   (2) Team: Team 1, Shift: Night, Start : 2016-11-01T19:00, End : 2016-11-02T07:00\n[3] Day: 2016-11-02\n   (1) Team: Team 2, Shift: Day, Start : 2016-11-02T07:00, End : 2016-11-02T19:00\n   (2) Team: Team 3, Shift: Night, Start : 2016-11-02T19:00, End : 2016-11-03T07:00\n[4] Day: 2016-11-03\n   (1) Team: Team 1, Shift: Day, Start : 2016-11-03T07:00, End : 2016-11-03T19:00\n   (2) Team: Team 2, Shift: Night, Start : 2016-11-03T19:00, End : 2016-11-04T07:00\n```\n \nFor a second example, the 24/7 schedule below has two rotations for four teams in two shifts.  It is used by manufacturing companies.\n\n```java\nWorkSchedule schedule = new WorkSchedule(\"Manufacturing Company - four twelves\",\n\t\"Four 12 hour alternating day/night shifts\");\n\n// day shift, start at 07:00 for 12 hours\nShift day = schedule.createShift(\"Day\", \"Day shift\", LocalTime.of(7, 0, 0), Duration.ofHours(12));\n\n// night shift, start at 19:00 for 12 hours\nShift night = schedule.createShift(\"Night\", \"Night shift\", LocalTime.of(19, 0, 0), Duration.ofHours(12));\n\n// 7 days ON, 7 OFF\nRotation dayRotation = new Rotation(\"Day\", \"Day\");\ndayRotation.addSegment(day, 7, 7);\n\n// 7 nights ON, 7 OFF\nRotation nightRotation = new Rotation(\"Night\", \"Night\");\nnightRotation.addSegment(night, 7, 7);\n\nschedule.createTeam(\"A\", \"A day shift\", dayRotation, LocalDate.of(2014, 1, 2));\nschedule.createTeam(\"B\", \"B night shift\", nightRotation, LocalDate.of(2014, 1, 2));\nschedule.createTeam(\"C\", \"C day shift\", dayRotation, LocalDate.of(2014, 1, 9));\nschedule.createTeam(\"D\", \"D night shift\", nightRotation, LocalDate.of(2014, 1, 9));\n```\n\nWhen printed out for a week of shift instances, the output is:\n\n```java\nSchedule: Manufacturing Company - four twelves (Four 12 hour alternating day/night shifts)\nRotation duration: PT1344H, Scheduled working time: PT336H\nShifts: \n   (1) Day (Day shift), Start : 07:00 (PT12H), End : 19:00\n   (2) Night (Night shift), Start : 19:00 (PT12H), End : 07:00\nTeams: \n   (1) A (A day shift), Rotation start: 2014-01-02, Rotation periods: [Day (on), Day (on), Day (on), Day (on), Day (on), Day (on), Day (on), (off), (off), (off), (off), (off), (off), (off) ], Rotation duration: PT336H, Days in rotation: 14, Scheduled working time: PT84H, Percentage worked: 25%, Average hours worked per week: PT42H\n   (2) B (B night shift), Rotation start: 2014-01-02, Rotation periods: [Night (on), Night (on), Night (on), Night (on), Night (on), Night (on), Night (on), (off), (off), (off), (off), (off), (off), (off) ], Rotation duration: PT336H, Days in rotation: 14, Scheduled working time: PT84H, Percentage worked: 25%, Average hours worked per week: PT42H\n   (3) C (C day shift), Rotation start: 2014-01-09, Rotation periods: [Day (on), Day (on), Day (on), Day (on), Day (on), Day (on), Day (on), (off), (off), (off), (off), (off), (off), (off) ], Rotation duration: PT336H, Days in rotation: 14, Scheduled working time: PT84H, Percentage worked: 25%, Average hours worked per week: PT42H\n   (4) D (D night shift), Rotation start: 2014-01-09, Rotation periods: [Night (on), Night (on), Night (on), Night (on), Night (on), Night (on), Night (on), (off), (off), (off), (off), (off), (off), (off) ], Rotation duration: PT336H, Days in rotation: 14, Scheduled working time: PT84H, Percentage worked: 25%, Average hours worked per week: PT42H\nTotal team coverage: 100%\nWorking shifts\n[1] Day: 2014-01-09\n   (1) Team: C, Shift: Day, Start : 2014-01-09T07:00, End : 2014-01-09T19:00\n   (2) Team: D, Shift: Night, Start : 2014-01-09T19:00, End : 2014-01-10T07:00\n[2] Day: 2014-01-10\n   (1) Team: C, Shift: Day, Start : 2014-01-10T07:00, End : 2014-01-10T19:00\n   (2) Team: D, Shift: Night, Start : 2014-01-10T19:00, End : 2014-01-11T07:00\n[3] Day: 2014-01-11\n   (1) Team: C, Shift: Day, Start : 2014-01-11T07:00, End : 2014-01-11T19:00\n   (2) Team: D, Shift: Night, Start : 2014-01-11T19:00, End : 2014-01-12T07:00\n[4] Day: 2014-01-12\n   (1) Team: C, Shift: Day, Start : 2014-01-12T07:00, End : 2014-01-12T19:00\n   (2) Team: D, Shift: Night, Start : 2014-01-12T19:00, End : 2014-01-13T07:00\n[5] Day: 2014-01-13\n   (1) Team: C, Shift: Day, Start : 2014-01-13T07:00, End : 2014-01-13T19:00\n   (2) Team: D, Shift: Night, Start : 2014-01-13T19:00, End : 2014-01-14T07:00\n[6] Day: 2014-01-14\n   (1) Team: C, Shift: Day, Start : 2014-01-14T07:00, End : 2014-01-14T19:00\n   (2) Team: D, Shift: Night, Start : 2014-01-14T19:00, End : 2014-01-15T07:00\n[7] Day: 2014-01-15\n   (1) Team: C, Shift: Day, Start : 2014-01-15T07:00, End : 2014-01-15T19:00\n   (2) Team: D, Shift: Night, Start : 2014-01-15T19:00, End : 2014-01-16T07:00\n```\n\nFor a third example, the work schedule below with one 24 hour shift over an 18 day rotation for three platoons is used by Kern County California firefighters.\n\n```java\nWorkSchedule schedule = new WorkSchedule(\"Kern Co.\", \"Three 24 hour alternating shifts\");\n\n// shift, start 07:00 for 24 hours\nShift shift = schedule.createShift(\"24 Hour\", \"24 hour shift\", LocalTime.of(7, 0, 0), Duration.ofHours(24));\n\n// 2 days ON, 2 OFF, 2 ON, 2 OFF, 2 ON, 8 OFF\nRotation rotation = new Rotation(\"24 Hour\", \"2 days ON, 2 OFF, 2 ON, 2 OFF, 2 ON, 8 OFF\");\nrotation.addSegment(shift, 2, 2);\nrotation.addSegment(shift, 2, 2);\nrotation.addSegment(shift, 2, 8);\n\nTeam platoon1 = schedule.createTeam(\"Red\", \"A Shift\", rotation, LocalDate.of(2017, 1, 8));\nTeam platoon2 = schedule.createTeam(\"Black\", \"B Shift\", rotation, LocalDate.of(2017, 2, 1));\nTeam platoon3 = schedule.createTeam(\"Green\", \"C Shift\", rotation, LocalDate.of(2017, 1, 2));\n```\n\nWhen printed out for a week of shift instances, the output is:\n```java\nSchedule: Kern Co. (Three 24 hour alternating shifts)\nRotation duration: PT1296H, Scheduled working time: PT432H\nShifts: \n   (1) 24 Hour (24 hour shift), Start : 07:00 (PT24H), End : 07:00\nTeams: \n   (1) Red (A Shift), Rotation start: 2017-01-08, Rotation periods: [24 Hour (on), 24 Hour (on), (off), (off), 24 Hour (on), 24 Hour (on), (off), (off), 24 Hour (on), 24 Hour (on), (off), (off), (off), (off), (off), (off), (off), (off) ], Rotation duration: PT432H, Days in rotation: 18, Scheduled working time: PT144H, Percentage worked: 33.33%, Average hours worked per week: PT56H\n   (2) Black (B Shift), Rotation start: 2017-02-01, Rotation periods: [24 Hour (on), 24 Hour (on), (off), (off), 24 Hour (on), 24 Hour (on), (off), (off), 24 Hour (on), 24 Hour (on), (off), (off), (off), (off), (off), (off), (off), (off) ], Rotation duration: PT432H, Days in rotation: 18, Scheduled working time: PT144H, Percentage worked: 33.33%, Average hours worked per week: PT56H\n   (3) Green (C Shift), Rotation start: 2017-01-02, Rotation periods: [24 Hour (on), 24 Hour (on), (off), (off), 24 Hour (on), 24 Hour (on), (off), (off), 24 Hour (on), 24 Hour (on), (off), (off), (off), (off), (off), (off), (off), (off) ], Rotation duration: PT432H, Days in rotation: 18, Scheduled working time: PT144H, Percentage worked: 33.33%, Average hours worked per week: PT56H\nTotal team coverage: 100%\nWorking shifts\n[1] Day: 2017-02-01\n   (1) Team: Black, Shift: 24 Hour, Start : 2017-02-01T07:00, End : 2017-02-02T07:00\n[2] Day: 2017-02-02\n   (1) Team: Black, Shift: 24 Hour, Start : 2017-02-02T07:00, End : 2017-02-03T07:00\n[3] Day: 2017-02-03\n   (1) Team: Red, Shift: 24 Hour, Start : 2017-02-03T07:00, End : 2017-02-04T07:00\n[4] Day: 2017-02-04\n   (1) Team: Red, Shift: 24 Hour, Start : 2017-02-04T07:00, End : 2017-02-05T07:00\n[5] Day: 2017-02-05\n   (1) Team: Black, Shift: 24 Hour, Start : 2017-02-05T07:00, End : 2017-02-06T07:00\n[6] Day: 2017-02-06\n   (1) Team: Black, Shift: 24 Hour, Start : 2017-02-06T07:00, End : 2017-02-07T07:00\n[7] Day: 2017-02-07\n   (1) Team: Green, Shift: 24 Hour, Start : 2017-02-07T07:00, End : 2017-02-08T07:00\n```\n\nFor a fourth example, for a restaurant shift starting at 7 am on August 8, 2024, team member #1 called in sick and is to be replaced by member #10:\n```java\n// Sunday team\nTeam sundayDay = schedule.createTeam(\"SundayDay\", \"Sunday day\", dayRotation, LocalDate.of(2024, 7, 28);\n\t\t\n// chef members\nTeamMember one = new TeamMember(\"Chef, One\", \"Chef\", \"1\");\nTeamMember ten = new TeamMember(\"Ten\", \"Ten description\", \"10\");\n\nsundayDay.addMember(one);\n...\n// replace one with ten\nLocalDateTime exceptionShift = LocalDateTime.of(LocalDate.of(2024, 8, 11), LocalTime.of(7, 0, 0));\nTeamMemberException replacement = new TeamMemberException(exceptionShift);\nreplacement.setRemoval(one);\nreplacement.setAddition(ten);\nsundayDay.addMemberException(replacement);\n\n// #1 is in the assigned list\nList\u003cTeamMember\u003e members = sundayDay.getAssignedMembers();\n\n// but is replaced by #10 for that shift instance:\nmembers = sundayDay.getMembers(exceptionShift);\n```\n\n## Maven Central Repository\nAdd this dependency to your pom.xml file:\n```java\n\u003cdependency\u003e\n\u003cgroupId\u003eorg.point85\u003c/groupId\u003e\n\u003cartifactId\u003eworkschedule\u003c/artifactId\u003e\n\u003cversion\u003e1.2.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n## Project Structure\nShift depends upon Java 8+ due to use of the java date and time classes.  The unit tests depend on JUnit (http://junit.org/junit4/) and Hamcrest (http://hamcrest.org/).\n\nShift has the following structure:\n * `/javadoc` javadoc  zip file\n * `/doc` documentation\n * `/src/main/java` - java source files\n * `/src/main/resources` - localizable .properties file to define error messages.\n * `/src/test/java` - JUnit test java source files\n \nThe binary jar file can be accessed by clicking on the \"releases\" link.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpoint85%2Fshift","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpoint85%2Fshift","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpoint85%2Fshift/lists"}