如何按指定间隔拆分两个YYYYmm格式日期区间的月份?
日期区间按指定月数拆分的解决方案
问题描述
我有两个YYYYmm格式的日期:start为202307,end为202612。希望按照指定间隔拆分该日期区间,例如调用split_months('202307','202405',5)时,期望返回结果(('202307','202311'), ('202312','202404'), ('202405','202405'))。我尝试了以下代码但逻辑存在问题,请求相关解决建议:
def split_months(start, end, intv): from datetime import datetime periodList = [] periodRangeSplitList = [] start = datetime.strptime(start ,"%Y%m") end = datetime.strptime(end ,"%Y%m") mthDiff = relativedelta.relativedelta(end, start) if mthDiff == 0: periodRangeSplitList.append((start,start)) return periodRangeSplitList diff = mthDiff / intv print(diff) for i in range(intv): periodList.append ((start + diff * i).strftime("%Y%m")) periodList.append(end.strftime("%Y%m")) print(periodList)
问题分析
原代码存在以下核心问题:
- 直接对
relativedelta对象做除法运算会导致精度偏差,无法精准计算区间起止日期 - 循环仅生成零散日期点,未组装成要求的区间元组格式
- 未处理最后一个区间不足指定间隔的边界情况
解决方案
以下是修正后的代码,核心思路是先计算总月数差,再逐个生成每个区间的起止日期:
from datetime import datetime from dateutil.relativedelta import relativedelta def split_months(start_str, end_str, intv): # 转换为datetime对象,方便日期运算 start = datetime.strptime(start_str, "%Y%m") end = datetime.strptime(end_str, "%Y%m") # 计算两个日期之间的总月数差 total_months = (end.year - start.year) * 12 + (end.month - start.month) result = [] # 处理起止日期相同的特殊情况 if total_months == 0: return ((start_str, end_str),) current_start = start while current_start <= end: # 计算当前区间的结束日期:起始日期 + 间隔月数 -1 current_end = current_start + relativedelta(months=intv - 1) # 如果计算出的结束日期超过最终终点,就用最终日期作为区间结束 if current_end > end: current_end = end # 转换为YYYYmm格式的字符串 start_formatted = current_start.strftime("%Y%m") end_formatted = current_end.strftime("%Y%m") result.append((start_formatted, end_formatted)) # 更新下一个区间的起始日期:当前结束日期 +1个月 current_start = current_end + relativedelta(months=1) return tuple(result)
代码说明
- 日期转换:将输入的字符串日期转为
datetime对象,便于后续的月份加减运算 - 总月数计算:通过年份差和月份差计算总月数,避免
relativedelta直接运算的精度问题 - 区间生成逻辑:
- 从起始日期开始,每次生成一个长度为
intv个月的区间(最后一个区间可能不足) - 若当前计算的结束日期超出最终终点,则以最终日期作为该区间的结束
- 将每个区间的起止日期转为指定格式后加入结果列表
- 从起始日期开始,每次生成一个长度为
- 结果返回:将结果列表转为元组,匹配示例中的返回格式要求
测试示例
调用split_months('202307','202405',5),返回结果为:
(('202307', '202311'), ('202312', '202404'), ('202405', '202405'))
与期望完全一致。
内容的提问来源于stack exchange,提问作者Maria
相关产品推荐
相关产品推荐

