业务场景说明:最近接到一个产品的需求,要求获取某个人,在某一天从上午9点到下午18点内超过两个小时的时间段范围列表,后面用于后继插入其他工作.....
感受:资本家的每个毛孔里都渗透着血和肮脏的东西....吐槽哈, 不要见怪,不要见外,大家都知道哈。
吐槽终究是吐槽,我还不是在被压榨的过程中缓慢前行么,不被压榨,咋生活呀。
本次实现其实是在排班系统存在的前提下,可以获取某人未来的排班信息,用于后期做分段切割的基础数据。下图就是比较直白的展示了24小时内全部空余时间和工作时间的线路图。
那应该如何实现呢?应该如何取出所有的时间段?开始和结束时间如何限制?2h又是如何让计算呢?
我觉得应该需求三个参数去实现,分别是 unitTimeList (占用的时间列表) 、beginTime (开始时间)、endTime(结束时间)。?用开始时间和结束时间确定时间轴,占用时间列表是需要在时间轴中去除的。因此通过这三个参数就能完成上面业务了。
timeService.getIntervalTime(unitTimeList, startTime, endTime);
可是这个函数应该如何实现里面的服务呢??
- 获取日期区间内每一天的开始和结束时间戳
- 根据日期分组
- 设置unitTimeList?到时间轴里面,如果当日无占用列表数据,那么返回一整天
- 否则,根据开始时间排序
- 如果当前日期的开始时间与结束时间都在范围内,说明,这天排满了,返回就成。
详细实现还是请跑下面的代码吧...不太好解释...像是算法这玩意一样,有时还真是要一步步跑,才能懂呀。
这次用到两个包分别如下:
<dependencies>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>23.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.7</version>
</dependency>
</dependencies>
?用到的实体?UnitTime、 DateTimeStamp
public class UnitTime {
/**
* 当天日期 YYYY-MM-dd
*/
private String dateTime;
/**
* 开始时间戳
*/
private Long startDate;
/**
* 结束时间戳
*/
private Long endDate;
public UnitTime() {
}
}
public class DateTimeStamp {
private Long startTimeStamp;
private Long endTimeStamp;
public DateTimeStamp() {
}
public Long getStartTimeStamp() {
return startTimeStamp;
}
public void setStartTimeStamp(Long startTimeStamp) {
this.startTimeStamp = startTimeStamp;
}
public Long getEndTimeStamp() {
return endTimeStamp;
}
public void setEndTimeStamp(Long endTimeStamp) {
this.endTimeStamp = endTimeStamp;
}
}
具体的实现类?
public class TimeServiceImpl {
/**
* 获取开始日期到结束日期的空闲时间
*
* @param unitTimeList 占用的时间列表
* @param beginTime 开始时间
* @param endTime 结束时间
* @return
*/
public Map<String, List<DateTimeStamp>> getIntervalTime(List<UnitTime> unitTimeList, String beginTime, String endTime) throws ParseException {
Map<String, List<DateTimeStamp>> resultMap = Maps.newTreeMap();
// 获取日期区间内每一天的开始和结束时间戳
Map<String, DateTimeStamp> timeStampMap = DateUtil.getAllTimeStamp(beginTime, endTime);
//根据日期分组
Map<String, List<UnitTime>> unitTimeMap = unitTimeList.stream().collect(Collectors.groupingBy(UnitTime::getDateTime));
for (Map.Entry<String, DateTimeStamp> entry : timeStampMap.entrySet()) {
// currentUnitTimeList 当天的占用时间
List<UnitTime> currentUnitTimeList = unitTimeMap.get(entry.getKey());
List<DateTimeStamp> subList = Lists.newArrayList();
Long startTs = entry.getValue().getStartTimeStamp();
Long endTs = entry.getValue().getEndTimeStamp();
if (currentUnitTimeList.size() == 0) {
// 当天没有占用时间 则设置一整天的时间
DateTimeStamp resultTs = new DateTimeStamp();
resultTs.setStartTimeStamp(startTs);
resultTs.setEndTimeStamp(endTs);
subList.add(resultTs);
resultMap.put(entry.getKey(), subList);
continue;
}
// 根据开始时间排序
currentUnitTimeList.sort(Comparator.comparing(UnitTime::getStartDate));
for (UnitTime u : currentUnitTimeList) {
if (u.getStartDate().longValue() == startTs && u.getEndDate().longValue() == endTs) {
// 一整天全部占满
break;
}
if (u.getStartDate().longValue() > startTs) {
// 当前占用的开始时间戳大于当天的开始时间戳 则当天开始时间到当前的开始时间为空闲
DateTimeStamp resultTs = new DateTimeStamp();
resultTs.setStartTimeStamp(startTs);
resultTs.setEndTimeStamp(u.getStartDate().longValue());
subList.add(resultTs);
if (u.getEndDate().longValue() < endTs) {
// 当前结束时间戳小于当天结束时间戳 下一次循环的开始时间等于当前的结束时间
startTs = u.getEndDate().longValue();
if (currentUnitTimeList.get(currentUnitTimeList.size() - 1).getEndDate().longValue() == startTs) {
// 当前为数组最后一个元素 则当前结束时间到当天结束时间空闲
DateTimeStamp resultLastTs = new DateTimeStamp();
resultLastTs.setStartTimeStamp(startTs);
resultLastTs.setEndTimeStamp(endTs);
subList.add(resultLastTs);
}
} else {
break;
}
} else {
startTs = u.getEndDate().longValue();
}
}
resultMap.put(entry.getKey(), subList);
}
return resultMap;
}
}
用到的工具类?
public class DateUtil {
private static String LONGDATE_DATE = "yyyy-MM-dd";
public static Calendar getCalendar(Date date) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
return calendar;
}
/**
* 时间是否在本月内
*
* @param time 时间戳
* @param pattern 匹配格式
* @return
*/
public static boolean isThisTime(long time, String pattern) {
Date date = new Date(time);
SimpleDateFormat sdf = new SimpleDateFormat(pattern);
String param = sdf.format(date);
String now = sdf.format(new Date());
if (param.equals(now)) {
return true;
}
return false;
}
/**
* 获取时间段每天开始和结束的时间戳
*
* @param beginTime
* @param endTime
* @return
* @throws ParseException
*/
public static Map<String, DateTimeStamp> getAllTimeStamp(String beginTime, String endTime) throws ParseException {
Map<String, DateTimeStamp> allTimeStamp = Maps.newHashMap();
SimpleDateFormat sdf = new SimpleDateFormat(LONGDATE_DATE);
Calendar cal = getCalendar(sdf.parse(beginTime));
// 判断是否是同一天
if (isDay(beginTime, endTime)) {
setTimeStampList(allTimeStamp, cal);
return allTimeStamp;
}
//获取每天的开始和结束日期
setTimeStampList(allTimeStamp, cal);
while (true) {
cal.add(Calendar.DAY_OF_MONTH, 1);
if (sdf.parse(endTime).after(cal.getTime())) {
setTimeStampList(allTimeStamp, cal);
} else {
break;
}
}
setTimeStampList(allTimeStamp, cal);
return allTimeStamp;
}
/**
* 判断两个人日期是否为同一天
*
* @param beginDate
* @param endDate
* @return
* @throws ParseException
*/
public static boolean isDay(String beginDate, String endDate) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat(LONGDATE_DATE);
return DateUtils.isSameDay(sdf.parse(beginDate), sdf.parse(endDate));
}
private static void setTimeStampList(Map<String, DateTimeStamp> allTimeStamp, Calendar cal) {
DateTimeStamp dateTimeStamp = new DateTimeStamp();
long beginSt = getFirstTime(cal).getTime();
dateTimeStamp.setStartTimeStamp(beginSt);
long endSt = getLastTime(cal).getTime();
dateTimeStamp.setEndTimeStamp(endSt);
String result = new SimpleDateFormat("yyyy-MM-dd").format(new Date(beginSt));
allTimeStamp.put(result, dateTimeStamp);
}
/**
* 获取当天起始时间
*
* @param todayStart
* @return
*/
public static Date getFirstTime(Calendar todayStart) {
todayStart.set(Calendar.HOUR_OF_DAY, 9);
todayStart.set(Calendar.MINUTE, 0);
todayStart.set(Calendar.SECOND, 0);
todayStart.set(Calendar.MILLISECOND, 0);
return todayStart.getTime();
}
/**
* 获取当天结束时间
*
* @param todayEnd
* @return
*/
public static Date getLastTime(Calendar todayEnd) {
todayEnd.set(Calendar.HOUR_OF_DAY, 18);
todayEnd.set(Calendar.MINUTE, 0);
todayEnd.set(Calendar.SECOND, 0);
todayEnd.set(Calendar.MILLISECOND, 0);
return todayEnd.getTime();
}
}
可以用测试类测试一下?
public class TimeTest {
public static void main(String[] args) {
List<UnitTime> unitTimeList = Lists.newArrayList();
UnitTime unitTime = new UnitTime();
// 2019-11-03 09:00:00 - 2019-11-03 11:00:00
unitTime.setDateTime("2019-11-03");
unitTime.setStartDate(1572742800L);
unitTime.setEndDate(1572750000L);
unitTimeList.add(unitTime);
// 2019-11-03 13:20:00 - 2019-11-03 13:50:00
UnitTime unitTime2 = new UnitTime();
unitTime2.setDateTime("2019-11-03");
unitTime2.setStartDate(1572758400L);
unitTime2.setEndDate(1572760200L);
unitTimeList.add(unitTime2);
// 2019-11-03 14:30:00 - 2019-11-03 18:00:00
UnitTime unitTime3 = new UnitTime();
unitTime3.setDateTime("2019-11-03");
unitTime3.setStartDate(1572762600L);
unitTime3.setEndDate(1572775200L);
unitTimeList.add(unitTime3);
TimeServiceImpl timeService = new TimeServiceImpl();
Map<String, List<DateTimeStamp>> intervalMap = null;
try {
intervalMap = timeService.getIntervalTime(unitTimeList, "2019-11-03", "2019-11-03");
} catch (ParseException e) {
e.printStackTrace();
}
System.out.println(intervalMap);
}
最终的结果:?
?
?
|