近期在做一项目的过程中,需要涉及到服务人员班次、请假及服务预定等一系列时间管理问题,最后要提供出人员空闲的时间段以供用户选择,归结到底,涉及到两大时间算法,一是时间过滤,即在原定上班班次安排的基础上扣除休假、请假以及已预定的时间段,另一个是时间段合并,需要将一个服务涉及的多位服务人员的有效时间合并,以便用户先选择时间,而后选择该时间段有空的服务人员。下面将分享一下涉及时间的两个算法。
1、合并集合中的各时间段
原始数据:
startTime=2015-05-26 12:06:00 endTime=2015-05-26 15:06:00
startTime=2015-05-27 16:08:00 endTime=2015-05-27 19:08:00
startTime=2015-05-27 13:10:00 endTime=2015-05-27 16:10:00
startTime=2015-05-27 14:57:00 endTime=2015-05-27 17:57:00
startTime=2015-05-27 10:16:00 endTime=2015-05-27 13:16:00
startTime=2015-05-26 11:50:00 endTime=2015-05-26 13:50:00
startTime=2015-05-26 13:46:00 endTime=2015-05-26 16:46:00
startTime=2015-05-27 9:09:00 endTime=2015-05-27 12:09:00
startTime=2015-05-27 16:36:00 endTime=2015-05-27 18:36:00
startTime=2015-05-26 14:39:00 endTime=2015-05-26 16:39:00
结果:
startTime=2015-05-26 11:50:00 endTime=2015-05-26 16:46:00
startTime=2015-05-27 9:09:00 endTime=2015-05-27 19:08:00
核心代码
public static List<EmptyDuration> MergeDateTime(List<EmptyDuration> emptyDurations) { List<EmptyDuration> results = new List<EmptyDuration>(); if (emptyDurations.Count == 0) { return results; } // 对原始数据进行排序 List<EmptyDuration> em = emptyDurations.OrderBy(p => p.StartTime).ToList<EmptyDuration>(); DateTime startTime = em[0].StartTime; DateTime endTime = em[0].EndTime; for (int i = 0; i < em.Count - 1; i++) { int j = i + 1; // 处理前后两个没有交叉重叠的情况 if (em[i].EndTime < em[j].StartTime) { results.Add(new EmptyDuration { StartTime = startTime, EndTime = endTime }); startTime = em[j].StartTime; endTime = em[j].EndTime; } else { endTime = em[i].EndTime > em[j].EndTime ? em[i].EndTime : em[j].EndTime; } } // 补上最后剩下的时间段 results.Add(new EmptyDuration { StartTime = startTime, EndTime = endTime }); return results; }其它辅助测试代码
public static void MergeTest(int num, int days) { List<EmptyDuration> timeList = GeneralDuration(num, days); List<EmptyDuration> list = MergeDateTime(timeList); } public static List<EmptyDuration> GeneralDuration(int count, int maxDateDiff) { Random random = new Random(DateTime.Now.Millisecond); List<EmptyDuration> list = new List<EmptyDuration>(); for (int i = 0; i < count; i++) { int hour = random.Next(9, 20); int hourDiff = random.Next(2, 4); int min = random.Next(60); int dateDiff = random.Next(0, maxDateDiff); DateTime startTime = DateTime.Now.Date.AddDays(dateDiff).AddHours(hour).AddMinutes(min); DateTime endTime = DateTime.Now.Date.AddDays(dateDiff).AddHours(hour).AddHours(hourDiff).AddMinutes(min); list.Add(new EmptyDuration { ArtificerId = 10002, ShopId = 20001, StartTime = startTime, EndTime = endTime }); } return list; }
在此代码中,左侧是服务人员原定上班时间集合,右侧是员工请假、预定所占时间集合。
原始数据(左):
startTime=2015-05-26 9:00:00 endTime=2015-05-26 22:00:00
startTime=2015-05-27 9:00:00 endTime=2015-05-27 22:00:00
startTime=2015-05-28 9:00:00 endTime=2015-05-28 22:00:00
原始数据(右):
startTime=2015-05-27 19:39:00 endTime=2015-05-27 21:39:00
startTime=2015-05-28 12:56:00 endTime=2015-05-28 15:56:00
startTime=2015-05-26 17:17:00 endTime=2015-05-26 20:17:00
startTime=2015-05-27 9:45:00 endTime=2015-05-27 12:45:00
startTime=2015-05-27 18:08:00 endTime=2015-05-27 20:08:00
startTime=2015-05-28 19:46:00 endTime=2015-05-28 22:46:00
startTime=2015-05-28 12:09:00 endTime=2015-05-28 15:09:00
startTime=2015-05-27 11:55:00 endTime=2015-05-27 13:55:00
startTime=2015-05-28 17:18:00 endTime=2015-05-28 20:18:00
startTime=2015-05-26 18:09:00 endTime=2015-05-26 20:09:00
结果:
startTime=2015-05-26 9:00:00 endTime=2015-05-26 17:17:00
startTime=2015-05-26 20:17:00 endTime=2015-05-26 22:00:00
startTime=2015-05-27 9:00:00 endTime=2015-05-27 9:45:00
startTime=2015-05-27 13:55:00 endTime=2015-05-27 18:08:00
startTime=2015-05-27 21:39:00 endTime=2015-05-27 22:00:00
startTime=2015-05-28 9:00:00 endTime=2015-05-28 12:09:00
startTime=2015-05-28 15:56:00 endTime=2015-05-28 17:18:00
核心代码
public static List<EmptyDuration> SubtractDateTime(List<EmptyDuration> minuend, List<EmptyDuration> subtrahend) { List<EmptyDuration> results = new List<EmptyDuration>(); if (minuend.Count == 0 ) { return results; } if (subtrahend.Count == 0) { return minuend; } // 对原始数据进行排序 List<EmptyDuration> lefts = minuend.OrderBy(p => p.StartTime).ToList<EmptyDuration>(); List<EmptyDuration> rights = subtrahend.OrderBy(p => p.StartTime).ToList<EmptyDuration>(); // 左右两个集合的指针 int lIndex = 0; int rIndex = 0; // 左右两个集合的元素数量 int lMax = lefts.Count; int rMax = rights.Count; DateTime startTime = DateTime.MinValue; DateTime endTime = DateTime.MinValue; // 左右指针是否要下移一位并获取元素数据 bool lIncrease = true; while (lIndex < lMax && rIndex < rMax) { if (lIncrease) { startTime = lefts[lIndex].StartTime; endTime = lefts[lIndex].EndTime; } lIncrease = false; // 处理两个集合当前元素存在交叉重叠的情况 if (endTime > rights[rIndex].StartTime && startTime < rights[rIndex].EndTime) { // 上班开始时间在请假预定时间之前 if (startTime < rights[rIndex].StartTime) { results.Add(new EmptyDuration { StartTime = startTime, EndTime = rights[rIndex].StartTime }); // 上班结束时间在请假预定结束时间之前 if (endTime <= rights[rIndex].EndTime) { lIncrease = true; } else { startTime = rights[rIndex].EndTime; rIndex++; } } else // 上班开始时间在请假预定时间之后 { // 上班结束在请假预定时间之后 if (endTime > rights[rIndex].EndTime) { startTime = rights[rIndex].EndTime; rIndex++; } else { lIncrease = true; } } } else { // 上班时间段在请假预定时间段之前 if (startTime < rights[rIndex].StartTime) { results.Add(new EmptyDuration { StartTime = startTime, EndTime = endTime }); lIncrease = true; } else { rIndex++; } } if (lIncrease) { lIndex++; } } // 处理剩余上班时间段 if (lIndex < lMax) { results.Add(new EmptyDuration { StartTime = startTime, EndTime = endTime }); for (int i = lIndex + 1; i < lMax; i++) { results.Add(new EmptyDuration { StartTime = lefts[i].StartTime, EndTime = lefts[i].EndTime }); } } return results; }其它辅助测试代码:
public static void SubtractTest(int num, int days) { List<EmptyDuration> leftList = GeneralDuration(days); List<EmptyDuration> rightList = GeneralDuration(num, days); List<EmptyDuration> list = SubtractDateTime(leftList, rightList); } public static List<EmptyDuration> GeneralDuration(int days) { List<EmptyDuration> list = new List<EmptyDuration>(); for (int i = 0; i < days; i++) { list.Add(new EmptyDuration { StartTime = DateTime.Now.Date.AddDays(i).AddHours(9), EndTime = DateTime.Now.Date.AddDays(i).AddHours(22) }); } return list; }
原文地址:http://blog.csdn.net/mole/article/details/46007029