Package: pyshiftsla
pyshiftslaHighly customizable SLA calculator and Work shift Generator, for any time-keeping and days-off policiesrepo:https://github.com/DurianDan/pyshiftslaPyPi:https://pypi.org/project/pyshiftsla/Installpip install pyshiftslaQuickstart - A case in Vietnam's Law:Let's calculateSLAandgenerate work shiftsfor anAmericanfemale employee, Working inVietnam, about to take maternity leave.Law references:(1);(2)1. She will have:4-monthofmaternity leave.Holidays leave:AllVietnamese holidays.1 dayfrom home country'sNew Year's days (2024-01-01) (same as Solar New Year in Vietnam) (+0 holiday leave)1 dayfrom home country's Independence Days (2024-07-04) (+1 holiday leave)Overtime shiftin theSolar New Year: from 13:30 to 14:30Plus random3 days off2. Configuration forShiftsBuilderfrompysla.shifts_builderimportShiftsBuilder,Shift,DateRangefromdatetimeimporttime,dateUS_WOMAN_LIVING_IN_VIETNAM_MATERNITY_LEAVE_4MONTHS_2024=ShiftsBuilder(workdays_weekly=[0,1,2,3,4],# weekday indexes: Monday to Fridaydaily_shifts=DailyShift([# Usual Morning shift: 8:30 to 11:45# Created using a string, easier to read but slowerShift.fromstr("08301145"),# Usual Afternoon shift: 13:30 to 18:00# Parsed the timestamps straight to parameters, fasterShift(start=time(13,30),end=time(18))]),days_off_ranges=[# you can parse `date` or `DateRange`date(2024,1,1),# SOLAR_NEW_YEARdate(2024,7,4),# US_INDEPENDENCE_DAYDateRange.fromstr("20240430-20240501"),#VIETNAM_VICTORY_DAYDateRange.fromstr("20240902-20240903"),#VIETNAM_INDEPENDENCE_DAY#VIETNAMESE_LUNAR_NEW_YEAR, Lunar DateRange will automatically turn into Solar DateRangeDateRange.fromstr("20240101-20240105",calendar_type="lunar")#VIETNAM_LUNAR_HUNG_KINGS_FESTIVALDateRange.fromstr("20240310",calendar_type="lunar")# 4 months of maternity leaveDateRange.fromstr("20240801-20241201"),date(2024,2,9),# custom days offdate(2024,6,3),# custom days offdate(2024,12,10),# custom days off],special_shifts=ShiftRange({# Urgent overtime in the Solar New Year# 13:30 to 14:30date(2024,1,1):DailyShift([Shift.fromstr("13301430")]),}),)3. GenerateShiftRangefor year 2024ShiftRangeworks like a dictionary, and can check the generatedShiftat a specificdate.generated_shiftrange=(# ShiftRange for 2024US_WOMAN_LIVING_IN_VIETNAM_MATERNITY_LEAVE_4MONTHS_2024.build_shifts_from_daterange(from_date=date(2024,1,1),to_date=date(2024,12,30)))# Get Shifts in New Year 2024-01-01generated_shiftrange[date(2024,1,1)]# [Shift(start=datetime.time(13, 30), end=datetime.time(14, 30))]# Get Shifts in a random working daygenerated_shiftrange[date(2024,2,8)]# [#   Shift(start=datetime.time(8, 30), end=datetime.time(11, 45)),#   Shift(start=datetime.time(13, 30), end=datetime.time(18, 0))# ]# Get Shifts in a day off (holiday leave) 2024-07-04# KeyError: datetime.date(2024, 2, 9)generated_shiftrange[date(2024,7,4)]generated_shiftrange.get(date(2024,7,4))# None4. Calculate SLA (service-level agreement)The result will be inMilliseconds:sla_millis=(US_WOMAN_lIVING_IN_VIETNAM_MATERNITY_LEAVE_4MONTHS_2024.calculate_sla(start_deal=datetime(2024,1,1,14),end_deal=datetime(2024,1,2,9,30),use_generated_shifts=True,# for faster execution,# reuse the cached results from `build_shifts_from_daterange`,# if "False", set re-generated `ShiftsRange` from `start_deal` to `end_deal`))sla_hours=sla_millis/(1000*60*60)# 1.5 hoursGlobalShiftsBuilderconfig for your company/teamfrompysla.shifts_builderimportShiftsBuilder,ShiftfromdatetimeimporttimeCOMPANY_SHIFTS_BUILDER=ShiftsBuilder(daily_shifts=DailyShift([Shift.fromstr("08301145"),# morning shift, created using a string, easier to read but slowerShift(start=time(13,30),end=time(18))# afternoon shift, parsed the timestamps straight to parameters, faster]),workdays_weekly=[0,1,2,3,4]# Monday to Friday)Copy config to a specificemployee.employee_takes_4_days_off=(COMPANY_SHIFTS_BUILDER.add_days_off_range([DateRange.fromstr("20241204-20241205"),# 2days offDateRange.fromstr("20241000-20241001")# 2days off],inplace=False# if `False` will return a copied `ShiftsBuilder`,# if `True`, will change `COMPANY_SHIFTS_BUILDER` and return `None`))