Created
February 23, 2022 10:49
-
-
Save pilosus/965a19bc96a7b166466f41e7db8501ff to your computer and use it in GitHub Desktop.
Schedule for two working days in proper working hours
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| from datetime import datetime, timedelta | |
| from dateutil.relativedelta import relativedelta | |
| # working hours: 10:00 to 18:59 | |
| day_start = 0 | |
| day_end = 23 | |
| work_start = 10 | |
| work_end = 18 | |
| week_start = 0 | |
| week_end = 6 | |
| offset_days = 2 | |
| def fit_into_range_evenly( | |
| value: int, | |
| from_start: int, | |
| from_end: int, | |
| to_start: int, | |
| to_end: int | |
| ) -> int: | |
| """ | |
| Map value from one range into another with even distribution | |
| https://stackoverflow.com/questions/5731863/mapping-a-numeric-range-onto-another | |
| """ | |
| slope = (to_end - to_start) / (from_end - from_start) | |
| to = to_start + slope * (value - from_start) | |
| return int(to) | |
| def offset_weekend(dt: datetime) -> datetime: | |
| """ | |
| Jump over weekend days | |
| """ | |
| if dt.weekday() <= 4: | |
| return dt | |
| return dt + timedelta(days=offset_days) | |
| def schedule_to_weekday(dt: datetime) -> datetime: | |
| to_hour = fit_into_range_evenly( | |
| value=dt.hour, | |
| from_start=day_start, | |
| from_end=day_end, | |
| to_start=work_start, | |
| to_end=work_end | |
| ) | |
| to_dt = dt + timedelta(days=offset_days) | |
| result = offset_weekend(to_dt).replace(hour=to_hour) | |
| return result | |
| d0 = datetime(2022, 2, 14, 6, 25, 11) | |
| # Monday too early | |
| s0 = schedule_to_weekday(d0) | |
| # datetime.datetime(2022, 2, 16, 12, 25, 11) | |
| r0 = relativedelta(s0, d0) | |
| # relativedelta(days=+2, hours=+6) | |
| d1 = datetime(2022, 2, 14, 13, 55, 12) | |
| # Monday working hours | |
| s1 = schedule_to_weekday(d1) | |
| # datetime.datetime(2022, 2, 16, 14, 55, 12) | |
| r1 = relativedelta(s1, d1) | |
| # relativedelta(days=+2, hours=+1) | |
| d2 = datetime(2022, 2, 14, 22, 43, 10) | |
| # Monday too late | |
| s2 = schedule_to_weekday(d2) | |
| # datetime.datetime(2022, 2, 16, 17, 43, 10) | |
| r2 = relativedelta(s2, d2) | |
| # relativedelta(days=+1, hours=+19) | |
| d3 = datetime(2022, 2, 17, 8, 15, 58) | |
| # Thursday too early | |
| s3 = schedule_to_weekday(d3) | |
| # datetime.datetime(2022, 2, 21, 12, 15, 58) # next Monday morning | |
| r3 = relativedelta(s3, d3) | |
| # relativedelta(days=+4, hours=+4) | |
| d4 = datetime(2022, 2, 20, 19, 49, 40) | |
| # Sunday too late | |
| s4 = schedule_to_weekday(d4) | |
| # datetime.datetime(2022, 2, 22, 16, 49, 40) # next Tuesday | |
| r4 = relativedelta(s4, d4) | |
| # relativedelta(days=+1, hours=+21) | |
| d5 = datetime(2022, 2, 19, 7, 29, 43) | |
| # Saturnday too early | |
| s5 = schedule_to_weekday(d5) | |
| # datetime.datetime(2022, 2, 21, 12, 29, 43) # next Monday | |
| r5 = relativedelta(s5, d5) | |
| # relativedelta(days=+2, hours=+5) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment