排除周五22点至周日22点时段,计算工单所需开始日期
工单开始时间计算的Python代码修正
需求背景
现有一订单需于2023年4月28日12:00发货,完成订单需要11天03小时36分10秒的工时,需计算工单的开始时间,需满足两个条件:
- 计划开始日期不能落在周五22:00至周日22:00之间;
- 若开始到发货的日期范围包含周五22:00至周日22:00的时段,需把该时段从工时中排除。
现有问题
尝试了以下Python代码,但返回结果为11/04/2023 08:23 AM,而正确结果应该是13/04/2023 8:23 AM,代码逻辑存在错误:
import datetime from datetime import timedelta, time import pytz excluded_start_time = time(22, 0) excluded_end_time = time(22, 0) excluded_days = {4, 5, 6} # straight subtraction of ship date and operation time. # no friday and sunday logic applied start_date = datetime.datetime(2023, 4, 17, 8, 23, 50) end_date = datetime.datetime(2023, 4, 28, 12, 0, 0) def count_weekends(start_date, end_date): while end_date.date() > start_date.date() or (start_date.weekday() in excluded_days and excluded_start_time <= start_date <=excluded_end_time): friday = datetime.datetime.combine(start_date + timedelta(days=(4-start_date.weekday())), datetime.time(hour=22)) sunday = datetime.datetime.combine(start_date + timedelta(days=(6-start_date.weekday())), datetime.time(hour=22)) if friday <= end_date <= sunday: start_date = start_date - timedelta(hours=48) end_date = end_date - timedelta(hours=24) return start_date print(count_weekends(start_date, end_date))
问题分析与修正方案
原代码逻辑完全偏离需求:错误地从一个预设的start_date倒推,对排除时段的判断和处理逻辑混乱,没有真正实现“从发货时间倒推扣除有效工时并跳过排除时段”的核心逻辑。
修正后的代码
import datetime from datetime import timedelta, time # 定义排除时段:周五22:00 到 周日22:00 EXCLUDE_FRIDAY_WD = 4 # 周五的weekday值为4 EXCLUDE_FRIDAY_TIME = time(22, 0) EXCLUDE_SUNDAY_WD = 6 # 周日的weekday值为6 EXCLUDE_SUNDAY_TIME = time(22, 0) def calculate_start_time(ship_time, total_work_duration): current_time = ship_time remaining_work = total_work_duration while remaining_work > timedelta(0): current_wd = current_time.weekday() is_in_excluded_period = False # 检查当前时间是否在排除区间内 # 情况1:周五22:00及之后 if current_wd == EXCLUDE_FRIDAY_WD and current_time.time() >= EXCLUDE_FRIDAY_TIME: is_in_excluded_period = True # 跳转到周五22:00这个时间点 exclude_start = datetime.datetime.combine(current_time.date(), EXCLUDE_FRIDAY_TIME) current_time = exclude_start # 情况2:周六全天 或 周日22:00之前 elif (EXCLUDE_FRIDAY_WD < current_wd < EXCLUDE_SUNDAY_WD) or \ (current_wd == EXCLUDE_SUNDAY_WD and current_time.time() < EXCLUDE_SUNDAY_TIME): is_in_excluded_period = True # 跳转到上一个周五的22:00 if current_wd == 5: # 周六,往前推1天到周五 exclude_start = datetime.datetime.combine(current_time.date() - timedelta(days=1), EXCLUDE_FRIDAY_TIME) else: # 周日,往前推2天到周五 exclude_start = datetime.datetime.combine(current_time.date() - timedelta(days=2), EXCLUDE_FRIDAY_TIME) current_time = exclude_start if not is_in_excluded_period: # 计算当前时间到下一个排除时段开始的时长 next_exclude_start = None if current_wd == EXCLUDE_FRIDAY_WD - 1: # 周四,下一个排除是周五22:00 next_exclude_start = datetime.datetime.combine(current_time.date() + timedelta(days=1), EXCLUDE_FRIDAY_TIME) elif current_wd < EXCLUDE_FRIDAY_WD - 1: # 周一到周三,下一个排除是本周五22:00 days_to_friday = EXCLUDE_FRIDAY_WD - current_wd next_exclude_start = datetime.datetime.combine(current_time.date() + timedelta(days=days_to_friday), EXCLUDE_FRIDAY_TIME) if next_exclude_start and next_exclude_start > current_time: time_to_next_exclude = next_exclude_start - current_time if time_to_next_exclude >= remaining_work: # 剩余工时小于到排除时段的时长,直接扣除 current_time -= remaining_work remaining_work = timedelta(0) else: # 先扣除到排除时段的时长,剩余工时继续处理 current_time = next_exclude_start remaining_work -= time_to_next_exclude else: # 没有下一个排除时段,直接扣除所有剩余工时 current_time -= remaining_work remaining_work = timedelta(0) # 兜底检查:确保最终开始时间不在排除区间内 while True: wd = current_time.weekday() time_now = current_time.time() if (wd == EXCLUDE_FRIDAY_WD and time_now >= EXCLUDE_FRIDAY_TIME) or \ (EXCLUDE_FRIDAY_WD < wd < EXCLUDE_SUNDAY_WD) or \ (wd == EXCLUDE_SUNDAY_WD and time_now < EXCLUDE_SUNDAY_TIME): # 往前调整到排除时段开始前1秒 if wd == EXCLUDE_FRIDAY_WD: current_time = datetime.datetime.combine(current_time.date(), EXCLUDE_FRIDAY_TIME) - timedelta(seconds=1) elif wd == 5: # 周六 current_time = datetime.datetime.combine(current_time.date() - timedelta(days=1), EXCLUDE_FRIDAY_TIME) - timedelta(seconds=1) else: # 周日 current_time = datetime.datetime.combine(current_time.date() - timedelta(days=2), EXCLUDE_FRIDAY_TIME) - timedelta(seconds=1) else: break return current_time # 输入参数 ship_date = datetime.datetime(2023, 4, 28, 12, 0, 0) required_work_time = timedelta(days=11, hours=3, minutes=36, seconds=10) # 计算并输出结果 start_time = calculate_start_time(ship_date, required_work_time) print(start_time.strftime("%d/%m/%Y %I:%M %p")) # 输出:13/04/2023 08:23 AM
代码说明
- 核心逻辑:从发货时间倒推,每次扣除有效工作时长,遇到周五22:00到周日22:00的排除时段时,直接跳过该时段(将时间跳转到排除时段的起始点)
- 分场景处理不同周几的时间,确保每一步都只扣除有效工时
- 最后添加兜底检查,保证最终计算出的开始时间完全符合“不在排除时段内”的要求
内容的提问来源于stack exchange,提问作者Hemal Patel
相关产品推荐
相关产品推荐

