Skip to content

Commit 0d1548c

Browse files
committed
- Updated to Python 3.13.4
- DayOff: changed start datetime to time in __int__ - Named: added Rotation.dayOff; Invalidated cached periods in addSegments() - Moved ShiftInstance to its own file - ShiftUtils: Use UTC to avoid timezone issues, improved formatTimedelta(), toRoundedSecond() - Standard rounding, improved compare() - Team: calculateWorkingTime() - rename toTime to toTimeOfDay - TeamMember: added setAddition() and setRemoval() - TimePeriod: changed start datetime to time in __int__; simplified timePlus() - WorkSchedule: fixed issue with deleteShift()
1 parent da8fea7 commit 0d1548c

17 files changed

Lines changed: 180 additions & 138 deletions

doc.zip

96.6 KB
Binary file not shown.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ exclude = [".settings", ".project", ".pydevproject", "README.md"]
1010

1111
[project]
1212
name = "PyWorkShift"
13-
version = "1.1.0"
13+
version = "1.1.1"
1414
keywords = ["shift", "work schedule", "shift calendar", "work calendar"]
1515
authors = [
1616
{ name="Kent Randall", email="point85.llc@gmail.com" },

release_notes.txt

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,15 @@ v1.0.2 January 11, 2024
1111

1212
v1.1.0 December 20, 2024
1313
- Added team members and shift exceptions for the team
14-
- Created a PyPI distribution
14+
- Created a PyPI distribution
15+
16+
v1.1.1 June 5, 2025
17+
- Updated to Python 3.13.4
18+
- DayOff: changed start datetime to time in __int__
19+
- Named: added Rotation.dayOff; Invalidated cached periods in addSegments()
20+
- Moved ShiftInstance to its own file
21+
- ShiftUtils: Use UTC to avoid timezone issues, improved formatTimedelta(), toRoundedSecond() - Standard rounding, improved compare()
22+
- Team: calculateWorkingTime() - rename toTime to toTimeOfDay
23+
- TeamMember: added setAddition() and setRemoval()
24+
- TimePeriod: changed start datetime to time in __int__; simplified timePlus()
25+
- WorkSchedule: fixed issue with deleteShift()

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
setup(
44
name = "PyShift",
55
packages = find_packages(),
6-
version = "1.1.0",
6+
version = "1.1.1",
77
description = "Work schedule library for Python",
88
author = "Kent Randall",
99
author_email = "point85.llc@gmail.com",

workschedule/day_off.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from PyShift.workschedule.time_period import TimePeriod
2-
from datetime import timedelta, datetime
2+
from datetime import timedelta, time
33

44
##
55
# Class DayOff represents a scheduled non-working period
@@ -16,7 +16,7 @@ class DayOff(TimePeriod):
1616
# @param start Date and time of day when period starts
1717
# @param duration Duration of day off
1818
#
19-
def __init__(self, name: str, description: str, start: datetime, duration: timedelta):
19+
def __init__(self, name: str, description: str, start: time, duration: timedelta):
2020
super().__init__(name, description, start, duration)
2121

2222
##
-7 Bytes
Binary file not shown.

workschedule/locales/en_US/LC_MESSAGES/schedule.po

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ msgid "shift.already.exists"
9999
msgstr "Shift {0} has already been created."
100100

101101
msgid "shift.in.use"
102-
msgstr "Shift {0} is being used in a work schedule."
102+
msgstr "Shift {0} is being used by team {1}."
103103

104104
msgid "nonworking.period.already.exists"
105105
msgstr "Non-working period {0} has already been created."

workschedule/named.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,20 @@ def __ne__(self, other) -> bool:
3131
return not self.__eq__(other)
3232

3333
def __lt__(self, other) -> bool:
34+
if other is None or not isinstance(other, Named):
35+
return NotImplemented
3436
return self.name < other.name
35-
37+
3638
def __gt__(self, other) -> bool:
37-
return self.name > other.name
39+
if other is None or not isinstance(other, Named):
40+
return NotImplemented
41+
return self.name > other.name
42+
43+
def __le__(self, other) -> bool:
44+
return self.name <= other.name
45+
46+
def __ge__(self, other) -> bool:
47+
return self.name >= other.name
3848

3949
def __str__(self) -> str:
4050
return self.name + " (" + self.description + ")"
@@ -45,6 +55,9 @@ def setName(self, name: str):
4555
raise PyShiftException(msg)
4656

4757
self.name = name
58+
59+
def setDescription(self, description: str):
60+
self.description = description or ""
4861

4962
##
5063
# Compare two Named objects by name

workschedule/rotation.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from datetime import datetime, time, timedelta, date
22
from operator import attrgetter
3+
from typing import List, Union
34

45
from PyShift.workschedule.named import Named
56
from PyShift.workschedule.localizer import Localizer
@@ -70,15 +71,15 @@ def __init__(self, name: str, description: str):
7071
def getDayOff() -> DayOff:
7172
if (Rotation.dayOff is None):
7273
midnight = datetime.combine(date.today(), time.min)
73-
dayOff = DayOff("DAY_OFF", "24 hour off period", midnight, timedelta(hours=24))
74-
return dayOff
74+
Rotation.dayOff = DayOff("DAY_OFF", "24 hour off period", midnight, timedelta(hours=24))
75+
return Rotation.dayOff
7576

7677
##
7778
# Get the shifts and off-shifts in the rotation
7879
#
7980
# @return List of periods
8081
#
81-
def getPeriods(self) -> []:
82+
def getPeriods(self) -> List[Union[Shift, DayOff]]:
8283
if (self.periods is None):
8384
self.periods = []
8485

@@ -147,6 +148,10 @@ def addSegment(self, startingShift: Shift, daysOn: int, daysOff: int) -> Rotatio
147148
segment = RotationSegment(startingShift, daysOn, daysOff, self)
148149
self.rotationSegments.append(segment)
149150
segment.sequence = len(self.rotationSegments)
151+
152+
# Invalidate cached periods
153+
self.periods = None
154+
150155
return segment
151156

152157
def __str__(self) -> str:
@@ -160,7 +165,7 @@ def __str__(self) -> str:
160165

161166
periods= ""
162167

163-
for period in self.periods:
168+
for period in self.getPeriods():
164169
if (len(periods) > 0):
165170
periods += ", "
166171

workschedule/shift.py

Lines changed: 1 addition & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from datetime import datetime, time, timedelta
1+
from datetime import time, timedelta
22

33
from PyShift.workschedule.time_period import TimePeriod
44
from PyShift.workschedule.work_break import Break
@@ -198,72 +198,4 @@ def __str__(self) -> str:
198198
text += "\n " + str(breakPeriod)
199199

200200
return text
201-
202-
##
203-
# Class ShiftInstance is an instance of a {@link Shift}. A shift instance is
204-
# worked by a {@link Team}.
205-
#
206-
class ShiftInstance:
207-
##
208-
# Construct an instance of a shift
209-
# @param shift {@link Shift} definition
210-
# @param startDateTime Starting date and time of day
211-
# @param team {link Team} working the shift instance
212-
def __init__(self, shift: Shift, startDateTime: datetime, team):
213-
# definition of the shift instance
214-
self.shift = shift
215-
216-
# start date and time of day
217-
self.startDateTime = startDateTime
218-
219-
# team working it
220-
self.team = team
221-
222-
##
223-
# Get the ending date and time of day
224-
#
225-
# @return datetime when shift ends
226-
#
227-
def getEndTime(self) -> datetime:
228-
return self.startDateTime + self.shift.duration
229-
230-
##
231-
# Compare this shift to another such period by start date and time of
232-
# day
233-
#
234-
# @param other Other shift instance
235-
#
236-
# @return -1 if less than, 0 if equal and 1 if greater than
237-
#
238-
def compareTo(self, other) -> int:
239-
value = 0
240-
241-
if (self.startDateTime < other.startDateTime):
242-
value = -1
243-
elif (self.startDateTime > other.startDateTime):
244-
value = 1
245-
return value
246-
247-
##
248-
# Determine if this time falls within the shift instance period
249-
#
250-
# @param dateTime Date and time to check
251-
# @return True if the specified time is in this shift instance
252-
#
253-
def isInShiftInstance(self, dateTime: datetime) -> bool:
254-
return (dateTime.compareTo(self.startDateTime) >= 0 and dateTime.compareTo(self.getEndTime()) <= 0)
255-
256-
def __str__(self) -> str:
257-
t = Localizer.instance().messageStr("team")
258-
s = Localizer.instance().messageStr("shift")
259-
ps = Localizer.instance().messageStr("period.start")
260-
pe = Localizer.instance().messageStr("period.end")
261-
members = Localizer.instance().messageStr("team.members")
262-
263-
text = " " + t + ": " + self.team.name + ", " + s + ": " + self.shift.name + ", " + ps + ": " + str(self.startDateTime) + ", " + pe + ": " + str(self.getEndTime()) + "\n" + members
264-
265-
for member in self.team.getMembers(self.startDateTime):
266-
text += "\n\t" + str(member)
267-
268-
return text
269201

0 commit comments

Comments
 (0)