You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

排除周五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

代码说明

  1. 核心逻辑:从发货时间倒推,每次扣除有效工作时长,遇到周五22:00到周日22:00的排除时段时,直接跳过该时段(将时间跳转到排除时段的起始点)
  2. 分场景处理不同周几的时间,确保每一步都只扣除有效工时
  3. 最后添加兜底检查,保证最终计算出的开始时间完全符合“不在排除时段内”的要求

内容的提问来源于stack exchange,提问作者Hemal Patel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 04:27:51