按工作时间计算请假时长
// 需求:根据考勤管理计算请假时长 // 1.考勤管理 包含工作日 + 节假日设置 // 举例 // 周一至周五 上班时间 9:00 - 18:00 中午休息时间 12:00 - 13:30 (实际工作时间长是7.5 如果请假 肯定也是请假时长7.5小时) // 节假日设置 10-1 至 10-7 为国庆节 节假日 // 问题请假时间范围为 2022-9-28 10:35 至 2022-10:9:14:35 的请假时长为多少分钟 // 先来看一个简单示例 今天上班时间为 9-18点 休息时间 12-13点休息 // 请假时间 为8点到15点 // 工作时间集合 设为集合A var A = new List<int> { 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 }; // 请假时间集合 设为集合B var B = new List<int> { 8, 9, 10, 11, 12, 13, 14, 15 }; // 休息时间集合 设为集合C var C = new List<int> { 12, 13, 17 }; // 首先请假时间长集合必须是在工作时间(A)和请假时间集合(C)之间由此可得到(A∩B) 意思是A集合和B集合的交集 // 因为存在休息时间所以必须排除休息时间集合(C) 则可得到(A∩B)-C 意思是(A交B)差C 白话文就是 先求A和B的交集D 在求D和C的差集 // A∩B ={9, 10, 11, 12, 13, 14, 15} // A∩B-C ={9, 10, 11, 14, 15} // 转化成代码 var collection = A.Intersect(B).Except(C); // 得到请假时长就是结果求总条数 var leaveTime = collection.Count(); // 输出结果5小时 // 在回过头计算 请假时间范围为 2022-9-28 10:35 至 2022-10:9:14:35 的请假时长为多少分钟 DateTime leaveTimeStart = new(2022, 09, 28, 10, 35, 00), leaveTimeEnd = new(2022, 10, 10, 14, 35, 00); // 得到开始请假时间集合 var b = GetDateTimeMinutes(leaveTimeStart, leaveTimeEnd); // 节假日集合 var holidays = new List<DateTime> { new(2022, 10, 1), new(2022, 10, 2), new(2022, 10, 3), new(2022, 10, 4), new(2022, 10, 5), new(2022, 10, 6), new(2022, 10, 7) }; // 周末 周六 周日 var workDays = new List<DayOfWeek> { DayOfWeek.Sunday, DayOfWeek.Saturday, }; // 工作时间集合 var a = new List<DateTime>(); // 休息时间集合 var c = new List<DateTime>(); // 总共请假的天数有那些 var dates = GetDateTimes(leaveTimeStart, leaveTimeEnd); foreach (var date in dates) { // 如果是节假日则排除不计算请假时长 if (holidays.Any(d => d == date.Date)) { continue; } // 如果是周末则排除不计算请假时长 if (workDays.Any(d => d == date.DayOfWeek)) { continue; } // 工作时间 var startWork = new DateTime(date.Year, date.Month, date.Day, 9, 0, 0); var endWork = new DateTime(date.Year, date.Month, date.Day, 18, 0, 0); a.AddRange(GetDateTimeMinutes(startWork, endWork)); // 休息时间 var startRest = new DateTime(date.Year, date.Month, date.Day, 12, 0, 0); var endRest = new DateTime(date.Year, date.Month, date.Day, 13, 30, 0); c.AddRange(GetDateTimeMinutes(startRest, endRest)); } // 得到请假分钟结果 var leaveMinutes = a.Intersect(b).Except(c).Count(); //请假时长 结果1500分钟 /* 2022-9-28 10:35 355分钟 这天为工作日请假时间为10:30到18:00 排除休息时间 355分钟 * 2022-9-29 450分钟 这天为工作日请假时间为09:00到18:00 排除休息时间 450分钟 * 2022-9-30 450分钟 这天为工作日请假时间为09:00到18:00 排除休息时间 450分钟 * 2022-10-11 14:35 245分钟 这天为工作日请假时间为09:00到14:35 排除休息时间 245分钟 * 结果 1500分钟 */
工具方法
/// <summary> /// 计算两个时间之间的分钟日期 /// </summary> /// <param name="startDate">开始日期</param> /// <param name="endDate">结束日期</param> /// <returns>日期集合</returns> /// <exception cref="ArgumentException">异常</exception> public static IEnumerable<DateTime> GetDateTimeMinutes(DateTime startDate, DateTime endDate) { if (endDate < startDate) { throw new ArgumentException(nameof(startDate)); } var result = new List<DateTime>(); for (var date = startDate; date < endDate; date = date.AddMinutes(1)) { result.Add(date); } return result; } /// <summary> /// 计算两个时间之间的日期 /// </summary> /// <param name="startDate">开始日期</param> /// <param name="endDate">结束日期</param> /// <returns>日期集合</returns> /// <exception cref="ArgumentException">异常</exception> public static IEnumerable<DateTime> GetDateTimes(DateTime startDate, DateTime endDate) { if (endDate < startDate) { throw new ArgumentException(nameof(startDate)); } var result = new List<DateTime>(); for (var date = startDate; date <= endDate; date = date.AddDays(1)) { result.Add(date); } return result; }