Itenso.TimePeriod计算时间区间天数交集结果异常问题排查
问题:Itenso.TimePeriod计算日期区间交集天数不符预期
我使用C#的Itenso.TimePeriod NuGet包计算两个日期区间的共同天数,但测试结果不符合预期:
测试场景:
- 区间1:2023-07-11 至 2023-07-15
- 区间2:2023-07-14 至 2023-08-01
预期交集天数为2天(7月14日、15日),但实际输出1天。
初始测试代码
var start1 = new DateTime(2023, 7, 11); var end1 = new DateTime(2023, 7, 15); var start2 = new DateTime(2023, 7, 14); var end2 = new DateTime(2023, 8, 1); var periods = new TimePeriodCollection { new TimeRange(start1, end1), new TimeRange(start2, end2), }; var periodIntersector = new TimePeriodIntersector<TimeRange>(); var intersectedPeriods = periodIntersector.IntersectPeriods(periods); Console.WriteLine($"intersected days: {intersectedPeriods.Duration.Days}");
修改后的代码及输出
尝试调整结束时间和区间闭合方式后,结果仍为1天:
var start1 = new DateTime(2023, 7, 11); var end1 = new DateTime(2023, 7, 15)+ TimeSpan.FromSeconds(1); var start2 = new DateTime(2023, 7, 14); var end2 = new DateTime(2023, 8, 1); var t1 = new TimeRange(start1, end1, true); var t2 = new TimeRange(start2, end2, true); var timeInterval1 = new TimeInterval(start1, end1); timeInterval1.EndEdge = IntervalEdge.Open; timeInterval1.StartEdge = IntervalEdge.Open; var timeInterval2 = new TimeInterval(start2, end2); timeInterval2.EndEdge = IntervalEdge.Open; timeInterval2.StartEdge = IntervalEdge.Open; var periods = new TimePeriodCollection { t1,t2 }; var periodIntersector = new TimePeriodIntersector<TimeRange>(); var intersectedPeriods = periodIntersector.IntersectPeriods(periods); Console.WriteLine($"intersected days: {intersectedPeriods.Duration.Days}"); Console.WriteLine($"intersected days: {t1.GetIntersection(t2).Duration.Days}");
输出:
intersected days: 1 intersected days: 1
问题原因与解决办法
核心原因
Itenso.TimePeriod中的TimeRange默认采用左闭右开的区间规则:
- 包含起始时间点
- 不包含结束时间点
初始测试中,end1 = new DateTime(2023,7,15)对应的是7月15日00:00:00,因此区间1实际覆盖的是2023-07-11 00:00:00 至 2023-07-15 00:00:00(不含),并不包含7月15日全天。两个区间的交集仅为7月14日一天,所以输出1天。
你尝试添加1秒的方式无效,因为结束时间变成7月15日00:00:01,区间仅包含这1秒,Duration.Days取整数部分仍为1。
正确解决方式
方式1:调整结束时间为次日0点(推荐)
将区间的结束时间设置为目标日期的次日0点,利用左闭右开规则覆盖目标日期全天:
var start1 = new DateTime(2023, 7, 11); // 结束时间设为7月16日0点,确保包含7月15日全天 var end1 = new DateTime(2023, 7, 16); var start2 = new DateTime(2023, 7, 14); var end2 = new DateTime(2023, 8, 1); var periods = new TimePeriodCollection { new TimeRange(start1, end1), new TimeRange(start2, end2), }; var periodIntersector = new TimePeriodIntersector<TimeRange>(); var intersectedPeriods = periodIntersector.IntersectPeriods(periods); Console.WriteLine($"intersected days: {intersectedPeriods.Duration.Days}"); // 输出:intersected days: 2
方式2:设置闭区间(包含起止时间)
显式将区间的StartEdge和EndEdge设为Closed,此时需要注意天数计算需基于实际区间覆盖范围调整:
var start1 = new DateTime(2023, 7, 11); var end1 = new DateTime(2023, 7, 15); var start2 = new DateTime(2023, 7, 14); var end2 = new DateTime(2023, 8, 1); // 创建闭区间 var t1 = new TimeRange(start1, end1) { StartEdge = IntervalEdge.Closed, EndEdge = IntervalEdge.Closed }; var t2 = new TimeRange(start2, end2) { StartEdge = IntervalEdge.Closed, EndEdge = IntervalEdge.Closed }; var intersection = t1.GetIntersection(t2); // 闭区间下,需额外判断是否包含结束日来计算完整天数 var days = (intersection.End - intersection.Start).Days + (intersection.EndEdge == IntervalEdge.Closed && intersection.End.TimeOfDay == TimeSpan.Zero ? 1 : 0); Console.WriteLine($"intersected days: {days}"); // 输出:intersected days: 2
内容的提问来源于stack exchange,提问作者Buda Gavril
相关产品推荐
相关产品推荐

