Skip to content

Commit e9ee8e3

Browse files
committed
Created a PyPI distribution at pip install PyWorkShift==1.0.2
1 parent 649cd00 commit e9ee8e3

File tree

4 files changed

+277
-5
lines changed

4 files changed

+277
-5
lines changed

LICENSE

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
MIT License
2-
3-
Copyright (c) 2021 Kent Randall
1+
Copyright (c) 2018 The Python Packaging Authority
42

53
Permission is hereby granted, free of charge, to any person obtaining a copy
64
of this software and associated documentation files (the "Software"), to deal
@@ -18,4 +16,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1816
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1917
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2018
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21-
SOFTWARE.
19+
SOFTWARE.

README_PyPI.md

+242
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
# PyShift
2+
The PyShift 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 PyShift 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.
3+
4+
## Concepts
5+
6+
The Business Management Systems' DNO (Day, Night, Off) work schedule with three teams and two 12-hour shifts with a 3-day rotation is an example work schedule. This schedule is explained in http://community.bmscentral.com/learnss/ZC/3T/c3tr12-1.
7+
8+
*Shift*
9+
10+
A 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.
11+
12+
*Team*
13+
14+
A 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.
15+
16+
*Work Schedule*
17+
18+
A 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.
19+
20+
After 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).
21+
22+
*Rotation*
23+
24+
A 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.
25+
26+
*Non-Working Period*
27+
28+
A 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.
29+
30+
*Shift Instance*
31+
32+
A 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.
33+
34+
## Examples
35+
The DNO schedule discussed above is defined as follows.
36+
37+
```python
38+
description = "This is a fast rotation plan that uses 3 teams and two 12-hr shifts to provide 24/7 coverage. "
39+
description = description + "Each team rotates through the following sequence every three days: 1 day shift, 1 night shift, and 1 day off."
40+
41+
self.workSchedule = WorkSchedule("DNO Plan", description)
42+
43+
# Day shift, starts at 07:00 for 12 hours
44+
day = self.workSchedule.createShift("Day", "Day shift", time(7, 0, 0), timedelta(hours=12))
45+
46+
# Night shift, starts at 19:00 for 12 hours
47+
night = self.workSchedule.createShift("Night", "Night shift", time(19, 0, 0), timedelta(hours=12))
48+
49+
# rotation
50+
rotation = self.workSchedule.createRotation("DNO", "DNO")
51+
rotation.addSegment(day, 1, 0)
52+
rotation.addSegment(night, 1, 1)
53+
referenceDate = date(2021, 11, 1)
54+
55+
self.workSchedule.createTeam("Team 1", "First team", rotation, referenceDate)
56+
self.workSchedule.createTeam("Team 2", "Second team", rotation, referenceDate - timedelta(days=1))
57+
self.workSchedule.createTeam("Team 3", "Third team", rotation, referenceDate - timedelta(days=2))
58+
```
59+
To obtain the working time over three days starting at 07:00, the following method is called:
60+
61+
```python
62+
fromDateTime = datetime.combine(date(2021, 11, 2), time(7, 0, 0))
63+
duration = self.workSchedule.calculateWorkingTime(fromDateTime, fromDateTime + timedelta(days=3))
64+
```
65+
66+
To obtain the shift instances for a date, the following method is called:
67+
68+
```python
69+
shiftInstances = self.workSchedule.getShiftInstancesForDay(date(2021, 11, 2))
70+
```
71+
72+
To print a work schedule, call the __str()__ method. For example:
73+
74+
```python
75+
print(str(self.workSchedule))
76+
```
77+
with output:
78+
79+
```python
80+
Schedule: 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.)
81+
Rotation duration: 9D:0H:0M, Scheduled working time: 3D:0H:0M
82+
Shifts:
83+
(1) Day (Day shift), Start: 07:00:00 (0D:12H:0M), End: 19:00:00
84+
(2) Night (Night shift), Start: 19:00:00 (0D:12H:0M), End: 07:00:00
85+
Teams:
86+
(1) Team 1 (First team), Rotation start: 2021-11-01, DNO (DNO)
87+
Rotation periods: [Day (on), Night (on), DAY_OFF (off)], Rotation duration: 3D:0H:0M, Days in rotation: 3.0, Scheduled working time: 1D:0H:0M, Percentage worked: 33.333%, Average hours worked per week: : 56.000
88+
(2) Team 2 (Second team), Rotation start: 2021-10-31, DNO (DNO)
89+
Rotation periods: [Day (on), Night (on), DAY_OFF (off)], Rotation duration: 3D:0H:0M, Days in rotation: 3.0, Scheduled working time: 1D:0H:0M, Percentage worked: 33.333%, Average hours worked per week: : 56.000
90+
(3) Team 3 (Third team), Rotation start: 2021-10-30, DNO (DNO)
91+
Rotation periods: [Day (on), Night (on), DAY_OFF (off)], Rotation duration: 3D:0H:0M, Days in rotation: 3.0, Scheduled working time: 1D:0H:0M, Percentage worked: 33.333%, Average hours worked per week: : 56.000
92+
Total team coverage: : 100.00%
93+
```
94+
95+
To print shift instances between two dates, the following method is called:
96+
97+
```python
98+
self.workSchedule.printShiftInstances(date(2021, 11, 1), date(2021, 11, 3))
99+
```
100+
with output:
101+
102+
```python
103+
Working shifts
104+
[1] Day: 2021-11-01
105+
(1) Team: Team 1, Shift: Day, Start: 2021-11-01 07:00:00, End: 2021-11-01 19:00:00
106+
(2) Team: Team 2, Shift: Night, Start: 2021-11-01 19:00:00, End: 2021-11-02 07:00:00
107+
[2] Day: 2021-11-02
108+
(1) Team: Team 3, Shift: Day, Start: 2021-11-02 07:00:00, End: 2021-11-02 19:00:00
109+
(2) Team: Team 1, Shift: Night, Start: 2021-11-02 19:00:00, End: 2021-11-03 07:00:00
110+
[3] Day: 2021-11-03
111+
(1) Team: Team 2, Shift: Day, Start: 2021-11-03 07:00:00, End: 2021-11-03 19:00:00
112+
(2) Team: Team 3, Shift: Night, Start: 2021-11-03 19:00:00, End: 2021-11-04 07:00:00
113+
```
114+
115+
For a second example, the 24/7 schedule below has two rotations for four teams in two shifts. It is used by manufacturing companies.
116+
117+
```python
118+
self.workSchedule = WorkSchedule("Manufacturing Company - four twelves",
119+
"Four 12 hour alternating day/night shifts")
120+
121+
# day shift, start at 07:00 for 12 hours
122+
day = self.workSchedule.createShift("Day", "Day shift", time(7, 0, 0), timedelta(hours=12))
123+
124+
# night shift, start at 19:00 for 12 hours
125+
night = self.workSchedule.createShift("Night", "Night shift", time(19, 0, 0), timedelta(hours=12))
126+
127+
# 7 days ON, 7 OFF
128+
dayRotation = self.workSchedule.createRotation("Day", "Day")
129+
dayRotation.addSegment(day, 7, 7)
130+
131+
# 7 nights ON, 7 OFF
132+
nightRotation = self.workSchedule.createRotation("Night", "Night")
133+
nightRotation.addSegment(night, 7, 7)
134+
135+
self.workSchedule.createTeam("A", "A day shift", dayRotation, date(2014, 1, 2))
136+
self.workSchedule.createTeam("B", "B night shift", nightRotation, date(2014, 1, 2))
137+
self.workSchedule.createTeam("C", "C day shift", dayRotation, date(2014, 1, 9))
138+
self.workSchedule.createTeam("D", "D night shift", nightRotation, date(2014, 1, 9))
139+
```
140+
141+
When printed out for a week of shift instances, the output is:
142+
143+
```python
144+
Schedule: Manufacturing Company - four twelves (Four 12 hour alternating day/night shifts)
145+
Rotation duration: 56D:0H:0M, Scheduled working time: 14D:0H:0M
146+
Shifts:
147+
(1) Day (Day shift), Start: 07:00:00 (0D:12H:0M), End: 19:00:00
148+
(2) Night (Night shift), Start: 19:00:00 (0D:12H:0M), End: 07:00:00
149+
Teams:
150+
(1) A (A day shift), Rotation start: 2014-01-02, Day (Day)
151+
Rotation periods: [Day (on), Day (on), Day (on), Day (on), Day (on), Day (on), Day (on), DAY_OFF (off), DAY_OFF (off), DAY_OFF (off), DAY_OFF (off), DAY_OFF (off), DAY_OFF (off), DAY_OFF (off)], Rotation duration: 14D:0H:0M, Days in rotation: 14.0, Scheduled working time: 3D:12H:0M, Percentage worked: 25.000%, Average hours worked per week: : 42.000
152+
(2) B (B night shift), Rotation start: 2014-01-02, Night (Night)
153+
Rotation periods: [Night (on), Night (on), Night (on), Night (on), Night (on), Night (on), Night (on), DAY_OFF (off), DAY_OFF (off), DAY_OFF (off), DAY_OFF (off), DAY_OFF (off), DAY_OFF (off), DAY_OFF (off)], Rotation duration: 14D:0H:0M, Days in rotation: 14.0, Scheduled working time: 3D:12H:0M, Percentage worked: 25.000%, Average hours worked per week: : 42.000
154+
(3) C (C day shift), Rotation start: 2014-01-09, Day (Day)
155+
Rotation periods: [Day (on), Day (on), Day (on), Day (on), Day (on), Day (on), Day (on), DAY_OFF (off), DAY_OFF (off), DAY_OFF (off), DAY_OFF (off), DAY_OFF (off), DAY_OFF (off), DAY_OFF (off)], Rotation duration: 14D:0H:0M, Days in rotation: 14.0, Scheduled working time: 3D:12H:0M, Percentage worked: 25.000%, Average hours worked per week: : 42.000
156+
(4) D (D night shift), Rotation start: 2014-01-09, Night (Night)
157+
Rotation periods: [Night (on), Night (on), Night (on), Night (on), Night (on), Night (on), Night (on), DAY_OFF (off), DAY_OFF (off), DAY_OFF (off), DAY_OFF (off), DAY_OFF (off), DAY_OFF (off), DAY_OFF (off)], Rotation duration: 14D:0H:0M, Days in rotation: 14.0, Scheduled working time: 3D:12H:0M, Percentage worked: 25.000%, Average hours worked per week: : 42.000
158+
Total team coverage: : 100.00%
159+
Working shifts
160+
[1] Day: 2021-11-01
161+
(1) Team: A, Shift: Day, Start: 2021-11-01 07:00:00, End: 2021-11-01 19:00:00
162+
(2) Team: B, Shift: Night, Start: 2021-11-01 19:00:00, End: 2021-11-02 07:00:00
163+
[2] Day: 2021-11-02
164+
(1) Team: A, Shift: Day, Start: 2021-11-02 07:00:00, End: 2021-11-02 19:00:00
165+
(2) Team: B, Shift: Night, Start: 2021-11-02 19:00:00, End: 2021-11-03 07:00:00
166+
[3] Day: 2021-11-03
167+
(1) Team: A, Shift: Day, Start: 2021-11-03 07:00:00, End: 2021-11-03 19:00:00
168+
(2) Team: B, Shift: Night, Start: 2021-11-03 19:00:00, End: 2021-11-04 07:00:00
169+
[4] Day: 2021-11-04
170+
(1) Team: C, Shift: Day, Start: 2021-11-04 07:00:00, End: 2021-11-04 19:00:00
171+
(2) Team: D, Shift: Night, Start: 2021-11-04 19:00:00, End: 2021-11-05 07:00:00
172+
[5] Day: 2021-11-05
173+
(1) Team: C, Shift: Day, Start: 2021-11-05 07:00:00, End: 2021-11-05 19:00:00
174+
(2) Team: D, Shift: Night, Start: 2021-11-05 19:00:00, End: 2021-11-06 07:00:00
175+
[6] Day: 2021-11-06
176+
(1) Team: C, Shift: Day, Start: 2021-11-06 07:00:00, End: 2021-11-06 19:00:00
177+
(2) Team: D, Shift: Night, Start: 2021-11-06 19:00:00, End: 2021-11-07 07:00:00
178+
[7] Day: 2021-11-07
179+
(1) Team: C, Shift: Day, Start: 2021-11-07 07:00:00, End: 2021-11-07 19:00:00
180+
(2) Team: D, Shift: Night, Start: 2021-11-07 19:00:00, End: 2021-11-08 07:00:00
181+
```
182+
183+
For 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.
184+
185+
```python
186+
# Kern Co, CA
187+
self.workSchedule = WorkSchedule("Kern Co.", "Three 24 hour alternating shifts")
188+
189+
# shift, start 07:00 for 24 hours
190+
shift = self.workSchedule.createShift("24 Hour", "24 hour shift", time(7, 0, 0), timedelta(hours=24))
191+
192+
# 2 days ON, 2 OFF, 2 ON, 2 OFF, 2 ON, 8 OFF
193+
rotation = self.workSchedule.createRotation("24 Hour", "2 days ON, 2 OFF, 2 ON, 2 OFF, 2 ON, 8 OFF")
194+
rotation.addSegment(shift, 2, 2)
195+
rotation.addSegment(shift, 2, 2)
196+
rotation.addSegment(shift, 2, 8)
197+
198+
self.workSchedule.createTeam("Red", "A Shift", rotation, date(2017, 1, 8))
199+
self.workSchedule.createTeam("Black", "B Shift", rotation, date(2017, 2, 1))
200+
self.workSchedule.createTeam("Green", "C Shift", rotation, date(2017, 1, 2))
201+
```
202+
203+
When printed out for a week of shift instances, the output is:
204+
```python
205+
Schedule: Kern Co. (Three 24 hour alternating shifts)
206+
Rotation duration: 54D:0H:0M, Scheduled working time: 18D:0H:0M
207+
Shifts:
208+
(1) 24 Hour (24 hour shift), Start: 07:00:00 (1D:0H:0M), End: 07:00:00
209+
Teams:
210+
(1) Red (A Shift), Rotation start: 2017-01-08, 24 Hour (2 days ON, 2 OFF, 2 ON, 2 OFF, 2 ON, 8 OFF)
211+
Rotation periods: [24 Hour (on), 24 Hour (on), DAY_OFF (off), DAY_OFF (off), 24 Hour (on), 24 Hour (on), DAY_OFF (off), DAY_OFF (off), 24 Hour (on), 24 Hour (on), DAY_OFF (off), DAY_OFF (off), DAY_OFF (off), DAY_OFF (off), DAY_OFF (off), DAY_OFF (off), DAY_OFF (off), DAY_OFF (off)], Rotation duration: 18D:0H:0M, Days in rotation: 18.0, Scheduled working time: 6D:0H:0M, Percentage worked: 33.333%, Average hours worked per week: : 56.000
212+
(2) Black (B Shift), Rotation start: 2017-02-01, 24 Hour (2 days ON, 2 OFF, 2 ON, 2 OFF, 2 ON, 8 OFF)
213+
Rotation periods: [24 Hour (on), 24 Hour (on), DAY_OFF (off), DAY_OFF (off), 24 Hour (on), 24 Hour (on), DAY_OFF (off), DAY_OFF (off), 24 Hour (on), 24 Hour (on), DAY_OFF (off), DAY_OFF (off), DAY_OFF (off), DAY_OFF (off), DAY_OFF (off), DAY_OFF (off), DAY_OFF (off), DAY_OFF (off)], Rotation duration: 18D:0H:0M, Days in rotation: 18.0, Scheduled working time: 6D:0H:0M, Percentage worked: 33.333%, Average hours worked per week: : 56.000
214+
(3) Green (C Shift), Rotation start: 2017-01-02, 24 Hour (2 days ON, 2 OFF, 2 ON, 2 OFF, 2 ON, 8 OFF)
215+
Rotation periods: [24 Hour (on), 24 Hour (on), DAY_OFF (off), DAY_OFF (off), 24 Hour (on), 24 Hour (on), DAY_OFF (off), DAY_OFF (off), 24 Hour (on), 24 Hour (on), DAY_OFF (off), DAY_OFF (off), DAY_OFF (off), DAY_OFF (off), DAY_OFF (off), DAY_OFF (off), DAY_OFF (off), DAY_OFF (off)], Rotation duration: 18D:0H:0M, Days in rotation: 18.0, Scheduled working time: 6D:0H:0M, Percentage worked: 33.333%, Average hours worked per week: : 56.000
216+
Total team coverage: : 100.00%
217+
Working shifts
218+
[1] Day: 2021-11-01
219+
(1) Team: Green, Shift: 24 Hour, Start: 2021-11-01 07:00:00, End: 2021-11-02 07:00:00
220+
[2] Day: 2021-11-02
221+
(1) Team: Green, Shift: 24 Hour, Start: 2021-11-02 07:00:00, End: 2021-11-03 07:00:00
222+
[3] Day: 2021-11-03
223+
(1) Team: Black, Shift: 24 Hour, Start: 2021-11-03 07:00:00, End: 2021-11-04 07:00:00
224+
[4] Day: 2021-11-04
225+
(1) Team: Black, Shift: 24 Hour, Start: 2021-11-04 07:00:00, End: 2021-11-05 07:00:00
226+
[5] Day: 2021-11-05
227+
(1) Team: Green, Shift: 24 Hour, Start: 2021-11-05 07:00:00, End: 2021-11-06 07:00:00
228+
[6] Day: 2021-11-06
229+
(1) Team: Green, Shift: 24 Hour, Start: 2021-11-06 07:00:00, End: 2021-11-07 07:00:00
230+
[7] Day: 2021-11-07
231+
(1) Team: Red, Shift: 24 Hour, Start: 2021-11-07 07:00:00, End: 2021-11-08 07:00:00
232+
```
233+
234+
## Project Structure
235+
PyShift has the following structure:
236+
* '/' - doc.zip (DOxygen documentation), setup.py, README.md
237+
* `/workschedule` - Python source files
238+
* `/workschedule/locales` - .mo and .po text translation files for locales
239+
* `/test` - unit test Python source files
240+
* `/scripts` - Windows shell script to create compiled message translation files
241+
242+

pyproject.toml

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
[build-system]
2+
requires = ["hatchling"]
3+
build-backend = "hatchling.build"
4+
5+
[tool.hatch.build.targets.wheel]
6+
packages = ["PyShift/workschedule"]
7+
8+
[tool.hatch.build.targets.sdist]
9+
exclude = [".settings", ".project", ".pydevproject", "README.md"]
10+
11+
[project]
12+
name = "PyWorkShift"
13+
version = "1.0.2"
14+
keywords = ["shift", "work schedule", "shift calendar", "work calendar"]
15+
authors = [
16+
{ name="Kent Randall", email="point85.llc@gmail.com" },
17+
]
18+
description = "A work schedule library for shifts."
19+
readme = "README_PyPI.md"
20+
requires-python = ">=3.1"
21+
classifiers = [
22+
"Programming Language :: Python :: 3",
23+
"License :: OSI Approved :: MIT License",
24+
"Operating System :: OS Independent",
25+
]
26+
27+
[project.urls]
28+
Homepage = "https://github.com/point85/PyShift"
29+
Issues = "https://github.com/point85/PyShift/issues"

release_notes.txt

+4-1
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,7 @@ v1.0.0 November 3, 2021
44
- Initial releasev1.0.0 November 3, 2021
55

66
v1.0.1 October 13, 2023
7-
- Updated for Python 3.12
7+
- Updated for Python 3.12
8+
9+
v1.0.2 January 11, 2024
10+
- Created a PyPI distribution

0 commit comments

Comments
 (0)