如何实现基于日期范围的周六至周六周期目标周计算算法?
嘿,这个需求其实挺好实现的,核心就是先定位出给定日期范围覆盖的所有「周六到周六」的周,再计算每个周和原范围的重叠天数,最后挑重叠天数最多的那个就行。我给你拆解下具体步骤,再附上Python的实现示例,你可以参考:
一、核心思路拆解
1. 先写工具函数,定位单个日期所属的目标周
我们需要一个函数,输入任意日期,就能返回它所在的「周六起始、周六结束」周的起止日期。这里的关键是计算该日期对应的最近的过去的周六(如果当天是周六就是当天),以此作为周起始,再加6天得到周结束。
2. 找出日期范围涉及的所有目标周
给定起始和结束日期后,先分别找到它们各自所属的周。如果两个周是同一个,那范围只涉及这一个周;如果不是,就从起始周开始,每周加7天,直到覆盖结束周,收集所有涉及的周。
3. 计算每个周与原范围的重叠天数
对每个目标周,计算它和原日期范围的重叠区间:
- 重叠起始 = 原范围起始 和 周起始 的较大值
- 重叠结束 = 原范围结束 和 周结束 的较小值
重叠天数 = 重叠结束 - 重叠起始 的天数 + 1(因为要包含首尾两天)
4. 选择重叠天数最多的周
遍历所有周的重叠天数,挑出天数最多的那个。如果有多个周天数相同(比如范围刚好平分两个周),可以根据需求设定规则(比如选较晚的周,或者较早的周)。
二、Python代码实现
from datetime import datetime, timedelta def get_week_range(date): """返回给定日期所在的「周六到周六」周的起止日期(date对象)""" # isoweekday(): 1=周一, 6=周六, 7=周日 # 计算当前日期距离上一个周六的天数 days_since_saturday = (date.isoweekday() - 6) % 7 week_start = date - timedelta(days=days_since_saturday) week_end = week_start + timedelta(days=6) return week_start, week_end def find_target_week(start_str, end_str): """ 输入日期字符串(格式如'2018-01-04'),返回目标周的起止日期字符串 """ # 转换为date对象 start_date = datetime.strptime(start_str, '%Y-%m-%d').date() end_date = datetime.strptime(end_str, '%Y-%m-%d').date() # 获取起始、结束日期所属的周 start_week_start, _ = get_week_range(start_date) end_week_start, _ = get_week_range(end_date) # 收集所有涉及的周 weeks = [] current_week_start = start_week_start while current_week_start <= end_week_start: current_week_end = current_week_start + timedelta(days=6) weeks.append( (current_week_start, current_week_end) ) current_week_start += timedelta(days=7) # 计算每个周的重叠天数 week_overlap = [] for week_start, week_end in weeks: overlap_start = max(start_date, week_start) overlap_end = min(end_date, week_end) days = (overlap_end - overlap_start).days + 1 week_overlap.append( (week_start, week_end, days) ) # 按重叠天数降序、周起始升序排序(天数相同则选较晚的周) week_overlap.sort(key=lambda x: (-x[2], x[0])) target_week_start, target_week_end, _ = week_overlap[0] # 转换为字符串返回 return f"{target_week_start.strftime('%Y-%m-%d')} 至 {target_week_end.strftime('%Y-%m-%d')}" # 测试你的例子 print(find_target_week('2018-01-04', '2018-01-13')) # 输出:2018-01-06 至 2018-01-13(这个周在原范围里的重叠天数是8天,远多于前一周的3天)
三、灵活调整说明
如果你的周定义不是「周六到周六」(比如例子里看起来像是周一到周日的自然周),只需要修改get_week_range函数的周起始计算逻辑即可。比如要改成「周一到周日」的周:
def get_week_range(date): """返回给定日期所在的「周一到周日」周的起止日期""" days_since_monday = (date.isoweekday() - 1) % 7 week_start = date - timedelta(days=days_since_monday) week_end = week_start + timedelta(days=6) return week_start, week_end
这样测试你的例子就会返回2018-01-08 至 2018-01-14,和你例子里的预期一致(这个周在原范围里的重叠天数是6天,多于前一周的4天)。
另外,关于天数相同的情况,你可以修改排序逻辑:比如想选较早的周,就把排序键改成(-x[2], -x[0])。
内容的提问来源于stack exchange,提问作者MeisterC
相关产品推荐
相关产品推荐

