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

如何设计可基于传入参数执行两类计算的业务日期时间服务类?

嘿,刚好我最近也在做类似的业务日期时间计算器服务类,结合你的需求,分享一下我梳理的设计思路和实现要点:

核心设计框架

这个服务类的核心是把自定义规则(工作排班、节假日)和计算逻辑解耦,让所有计算方法都基于初始化时传入的规则运行,这样扩展性和灵活性拉满。

初始化参数(重中之重)

初始化时必须传入两个核心参数,这是所有计算的基础:

  • 自定义工作时长:用字典work_hours来存储,键是星期的编号(建议用datetime.weekday()的返回值,0=周一,6=周日),值是该星期对应的工作时段列表。比如周二到周四的排班可以写成:
    work_hours = {
        1: [(time(9, 0), time(18, 0))],  # 周二
        2: [(time(9, 0), time(18, 0))],  # 周三
        3: [(time(9, 0), time(17, 0))]   # 周四(提前1小时下班)
    }
    
    这样还能支持单日多时段的场景,比如带午休的排班:[(time(9,0), time(12,0)), (time(13,0), time(18,0))]
  • 节假日集合:用Set[date]来存储所有非工作日的日期,比如法定节假日、公司自定义假期,这样判断的时候能快速O(1)查询。

核心功能方法实现

我把几个核心需求拆解成了独立的方法,每个方法都依赖基础的工作日判断逻辑:

1. 判断给定日期是否处于工作时段

这个是最基础的方法,分两步校验:

  • 先确认该日期是工作日(在work_hours中有对应排班,且不在节假日集合里)
  • 再检查给定的时间是否落在该日的任意一个工作时段内
    代码示例大概是这样:
def is_in_work_hours(self, target_datetime: datetime) -> bool:
    target_date = target_datetime.date()
    # 先判断是不是工作日
    if target_date.weekday() not in self.work_hours or target_date in self.holidays:
        return False
    target_time = target_datetime.time()
    # 遍历当天的所有工作时段
    for start, end in self.work_hours[target_date.weekday()]:
        if start <= target_time <= end:
            return True
    return False

2. 计算给定日期后X个工作日的日期

这里要注意,如果起始时间在工作日的工作时段内,是否要考虑剩余时长?我默认实现的是返回第X个完整工作日的起始时间,逻辑如下:

  • 从起始日期的下一天开始遍历
  • 每遇到一个工作日(非节假日+有排班)就计数减1
  • 计数归0时,返回该工作日的第一个工作时段起始时间
    代码示例:
def add_work_days(self, start_datetime: datetime, days: int) -> datetime:
    if days <= 0:
        return start_datetime
    
    current_date = start_datetime.date()
    remaining_days = days
    
    while remaining_days > 0:
        current_date = current_date.replace(day=current_date.day + 1)
        # 检查是否是工作日
        if current_date.weekday() in self.work_hours and current_date not in self.holidays:
            remaining_days -= 1
    
    # 返回目标工作日的第一个工作时段起始时间
    first_work_start = self.work_hours[current_date.weekday()][0][0]
    return datetime.combine(current_date, first_work_start)

如果需要支持“按工作时长累加”(比如起始时间是周三下午3点,加4小时工作时长可能到周四上午),可以扩展这个方法,引入工作时长的计算逻辑。

3. 获取下一个工作日的起始时间

这个方法要分两种情况处理:

  • 如果当前时间在工作日的未开始的工作时段之前,返回当天该时段的起始时间
  • 如果当天的工作时段都过了,或者当前日期是非工作日,就往后找第一个工作日,返回其第一个工作时段的起始时间
    代码示例:
def get_next_workday_start(self, current_datetime: datetime) -> datetime:
    current_date = current_datetime.date()
    current_time = current_datetime.time()
    
    # 先检查当天是否还有未开始的工作时段
    if current_date.weekday() in self.work_hours and current_date not in self.holidays:
        for start, end in self.work_hours[current_date.weekday()]:
            if start > current_time:
                return datetime.combine(current_date, start)
    
    # 当天没机会了,找下一个工作日
    next_date = current_date
    while True:
        next_date = next_date.replace(day=next_date.day + 1)
        if next_date.weekday() in self.work_hours and next_date not in self.holidays:
            first_start = self.work_hours[next_date.weekday()][0][0]
            return datetime.combine(next_date, first_start)

关键细节处理

  • 非标准排班兼容:因为用字典存储星期到时段的映射,不管是周二到周四上班,还是周末单休,都能直接通过调整work_hours的键来实现,完全不需要修改计算逻辑
  • 节假日动态更新:如果节假日是动态生成的(比如每年的法定节假日),可以把初始化参数改成接收一个生成节假日集合的函数,或者提供一个update_holidays方法来动态更新
  • 时间边界处理:要注意time类型的比较,比如刚好是上班/下班时间点,要判定为属于工作时段(可根据业务需求灵活调整)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 03:25:45