如何按财年拆分指定日期范围的时间段(财年为每年7月1日至次年6月30日)
财年日期范围拆分解决方案
针对你提出的「财年为7月1日至次年6月30日,需将任意给定日期范围拆分为对应财年分段,首段起始为输入From_Date、末段结束为输入To_Date」的需求,我提供以下几种实用的技术实现方案:
SQL实现方案(支持主流数据库)
SQL Server 版本
使用递归CTE(公共表表达式)来生成分段,逻辑清晰且高效:
DECLARE @FromDate DATE = '2021-06-16' DECLARE @ToDate DATE = '2022-08-31' ;WITH FiscalYearSegments AS ( -- 初始化第一个分段:确定起始日期所在财年的结束点 SELECT SegmentStart = @FromDate, SegmentEnd = CASE WHEN MONTH(@FromDate) >=7 THEN DATEFROMPARTS(YEAR(@FromDate)+1,6,30) ELSE DATEFROMPARTS(YEAR(@FromDate),6,30) END UNION ALL -- 递归生成中间完整的财年分段 SELECT SegmentStart = DATEADD(DAY,1,SegmentEnd), SegmentEnd = DATEADD(YEAR,1,SegmentEnd) FROM FiscalYearSegments WHERE DATEADD(DAY,1,SegmentEnd) < @ToDate ) -- 最终输出,处理末段超过ToDate的情况 SELECT Start_Date = SegmentStart, End_Date = CASE WHEN SegmentEnd > @ToDate THEN @ToDate ELSE SegmentEnd END FROM FiscalYearSegments ORDER BY Start_Date;
MySQL 8.0+ 版本
同样使用递归CTE,适配MySQL的日期函数:
SET @FromDate = '2021-06-16'; SET @ToDate = '2022-08-31'; WITH RECURSIVE FiscalYearSegments AS ( SELECT @FromDate AS SegmentStart, CASE WHEN MONTH(@FromDate) >=7 THEN STR_TO_DATE(CONCAT(YEAR(@FromDate)+1,'-06-30'), '%Y-%m-%d') ELSE STR_TO_DATE(CONCAT(YEAR(@FromDate),'-06-30'), '%Y-%m-%d') END AS SegmentEnd UNION ALL SELECT DATE_ADD(SegmentEnd, INTERVAL 1 DAY), DATE_ADD(SegmentEnd, INTERVAL 1 YEAR) FROM FiscalYearSegments WHERE DATE_ADD(SegmentEnd, INTERVAL 1 DAY) < @ToDate ) SELECT SegmentStart AS Start_Date, IF(SegmentEnd > @ToDate, @ToDate, SegmentEnd) AS End_Date FROM FiscalYearSegments ORDER BY Start_Date;
Python实现方案
如果需要在应用层处理日期拆分,可以用Python的datetime模块实现:
from datetime import date, timedelta def split_fiscal_year(from_date: date, to_date: date): fiscal_segments = [] current_start = from_date while current_start <= to_date: # 计算当前起始日期所在财年的结束日期 if current_start.month >= 7: fiscal_end = date(current_start.year + 1, 6, 30) else: fiscal_end = date(current_start.year, 6, 30) # 确保分段结束不超过输入的To_Date current_end = min(fiscal_end, to_date) fiscal_segments.append((current_start, current_end)) # 准备下一个分段的起始日期 current_start = current_end + timedelta(days=1) return fiscal_segments # 示例调用 if __name__ == "__main__": from_date = date(2021, 6, 16) to_date = date(2022, 8, 31) segments = split_fiscal_year(from_date, to_date) # 按指定格式输出 for start, end in segments: print(f"{start.strftime('%d-%b-%Y')}, {end.strftime('%d-%b-%Y')}")
验证示例结果
针对你给出的测试输入From_Date:16-Jun-2021至To_Date:31-Aug-2022,上述方案都会输出符合要求的结果:
16-Jun-2021, 30-Jun-2021
01-Jul-2021, 30-Jun-2022
01-Jul-2022, 31-Aug-2022
内容的提问来源于stack exchange,提问作者user1463065
相关产品推荐
相关产品推荐

