Skip to content

Instantly share code, notes, and snippets.

@pilosus
Created February 23, 2022 10:49
Show Gist options
  • Select an option

  • Save pilosus/965a19bc96a7b166466f41e7db8501ff to your computer and use it in GitHub Desktop.

Select an option

Save pilosus/965a19bc96a7b166466f41e7db8501ff to your computer and use it in GitHub Desktop.
Schedule for two working days in proper working hours
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