求助:实现C#月度每周加班时长统计方法
修正月度每周加班时长统计方案
我来帮你搞定这个按周统计加班时长的问题!你的核心需求是按周日作为每周结束节点,统计指定月份内每周的总加班时长,原代码的分组逻辑确实存在周边界计算错误、无法正确获取周日日期、缺失无加班周条目这些问题,下面是修正后的完整方案:
问题分析
原代码的(q.Key.Date.Day + w)/7分组逻辑有三个关键问题:
- 仅通过日期天数偏移计算周数,没有遵循每周以周日为结束的规则,周边界完全错误
- 用
g.FirstOrDefault().Key获取的是分组中任意一条记录的日期,不是该周的周日,导致结果的Day字段不符合需求 - 没有处理当月内无加班记录的周,会缺失对应的统计条目
修正方案
我们换个思路:先确定每个加班日期所属周的周日日期作为分组键,再生成当月所有周日的列表,确保每个周都有对应的统计结果(无加班则时长为0)。
完整修正代码
readonly List<KeyValuePair<DateTime, TimeSpan>> overTimeList = new List<KeyValuePair<DateTime, TimeSpan>>(); // 调用方式保持不变 DateTime start = new DateTime(calendar1.CurrentDate.Year, calendar1.CurrentDate.Month, 1); DateTime stop = new DateTime(calendar1.CurrentDate.Year, calendar1.CurrentDate.Month, 1).AddMonths(1).AddDays(-1); var weeksOverTimeSum = WeeklyOverTime(start, stop); // 修正后的核心方法 private List<SundayWithWeekSum> WeeklyOverTime(DateTime startDate, DateTime stopDate) { // 1. 获取当月所有周日的列表,确保覆盖整个月份的所有周 var allMonthlySundays = GetAllSundaysInMonth(startDate.Year, startDate.Month); // 2. 过滤当月加班记录,按所属周的周日分组并汇总时长 var groupedOverTime = overTimeList .Where(entry => entry.Key >= startDate && entry.Key <= stopDate) .GroupBy(entry => GetSundayOfWeek(entry.Key.Date)) .ToDictionary(group => group.Key, group => new TimeSpan(group.Sum(item => item.Value.Ticks))); // 3. 构建最终结果:每个周日对应统计时长,无加班则为0 var result = allMonthlySundays.Select(sunday => new SundayWithWeekSum { Day = sunday, Balance = groupedOverTime.TryGetValue(sunday, out var total) ? total : TimeSpan.Zero }).ToList(); return result; } // 辅助方法:获取指定日期所在周的周日(每周以周日为结束节点) private DateTime GetSundayOfWeek(DateTime date) { // 处理DayOfWeek的索引规则:Sunday是0,其他从1(周一)到6(周六) int daysToAdd = (7 - (int)date.DayOfWeek) % 7; return date.AddDays(daysToAdd).Date; } // 辅助方法:获取指定年月的所有周日 private List<DateTime> GetAllSundaysInMonth(int year, int month) { var sundays = new List<DateTime>(); DateTime firstDayOfMonth = new DateTime(year, month, 1); // 找到当月第一个周日 int daysToFirstSunday = (7 - (int)firstDayOfMonth.DayOfWeek) % 7; DateTime currentSunday = firstDayOfMonth.AddDays(daysToFirstSunday); // 遍历添加所有当月的周日 while (currentSunday.Month == month) { sundays.Add(currentSunday); currentSunday = currentSunday.AddDays(7); } return sundays; } // 保持原类结构不变 class SundayWithWeekSum { public DateTime Day { get; set; } public TimeSpan Balance { get; set; } }
关键逻辑说明
GetSundayOfWeek方法:- 正确处理C#中
DayOfWeek的索引规则(周日为0),确保任何日期都能精准映射到其所在周的周日 - 比如6月3日(周一)会映射到6月9日(周日),6月9日当天直接返回自身
- 正确处理C#中
GetAllSundaysInMonth方法:- 生成当月所有的周日列表,确保即使某周没有加班记录,结果中也会出现该周日条目,时长为
TimeSpan.Zero - 针对2019年6月,会生成
6/2/2019、6/9/2019、6/16/2019、6/23/2019、6/30/2019这五个周日,完全匹配你的示例输出日期
- 生成当月所有的周日列表,确保即使某周没有加班记录,结果中也会出现该周日条目,时长为
分组与结果构建:
- 用周日作为分组键,确保每个组严格对应一周的加班记录
- 通过
ToDictionary快速查找每个周日对应的总时长,最后结合所有周日列表生成完整结果,不会遗漏任何周
测试验证
针对你提供的2019年6月测试数据,运行后会得到:
- 6/2/2019:时长00:00:00(无加班记录)
- 6/9/2019:00:13:00(12-11+13+13-14=13分钟)
- 后续周的时长也会按你的示例正确计算,完全符合需求
内容的提问来源于stack exchange,提问作者Mara
相关产品推荐
相关产品推荐

