最近在做一个功能,需要统计请假天数,按月统计。而实际的请假数据就包括跨月的情况,所以就出现一个这样的问题。要计算本月内的请假天数。实际上就是求两个时间段内的重复天数。
大概有三种思路:
一、常规思路
以程序员的常规思维来看,计算两个时间段内的重复天数,分为多种情况。包括 包含、相交、相离 另外还需要处理边界值。每种情况又有细分,比如包含,如果是请假范围包含月份范围,则取月份范围。如果月份范围包括请假范围,则直接取请假范围。这样一看,逻辑思考上就较为复杂,写出来的代码阅读性就不高,容易出现纰露。
二、非常规思路
再来看看非常规思路,第一种的缺点是逻辑较为复杂,容易出漏洞。那有没有逻辑简单的方法呢?其实我们可以这样,将月份范围内的所有日期全部放到一个list中,然后遍历这个list,每个日期元素在另一个时间段内,则说明当前日期重复。累计计数即可。这种方案,逻辑较为简单,也不会出现什么纰漏,然而却是有一个缺陷,性能不行!如果时间范围大了,用这种方式,岂不是循环越来越大,如果该方法用在循环统计中,就更加损耗性能。
三、进阶思路
那有没有既便于理解,逻辑简单,又比较高性能的方案呢?我们可以用,两个时间段中 较早的结束时间减去较晚的开始时间,这样得到的正数的天数+1就是重复的天数。如果得到的天数小于0则说明两个时间段不重复。是不是非常简单呢!
/**
* 判断两个时间段的重叠天数
* @param startDate1
* @param endDate1
* @param startDate2
* @param endDate2
* @return
*/
public static long overLappingDayCount(LocalDate startDate1,LocalDate endDate1,LocalDate startDate2,LocalDate endDate2){
long dayCount=0l;
Boolean startBeforeFlag=startDate1.isBefore(startDate2);
Boolean endBeforeFlag=endDate1.isBefore(endDate2);
// 比较开始时间
LocalDate compareStartDate=null;
// 比较结束时间
LocalDate compareEndDate=null;
// 取比较晚的开始时间
if(startBeforeFlag){
compareStartDate=startDate2;
}else{
compareStartDate=startDate1;
}
// 取比较早的结束时间
if(endBeforeFlag){
compareEndDate=endDate1;
}else{
compareEndDate=endDate2;
}
// 计算相差天数 用比较早的结束时间-比较晚的开始时间
dayCount=DateUtils.until(compareStartDate,compareEndDate);
// 如果相差天数小于0 则说明没有重复天数 返回0即可
if(dayCount<0){
return 0;
}
// 如果相差天数大于等于0 则 重叠天数需要+1
dayCount++;
return dayCount;
}
public static void main(String[] args) {
LocalDate startDate1=DateUtils.parseLocalDate("2020-11-01",DEFAULT_DATE_FORMAT);
LocalDate endDate1=DateUtils.parseLocalDate("2020-11-30",DEFAULT_DATE_FORMAT);
LocalDate startDate2=DateUtils.parseLocalDate("2020-11-02",DEFAULT_DATE_FORMAT);
LocalDate endDate2=DateUtils.parseLocalDate("2020-12-05",DEFAULT_DATE_FORMAT);
long dayCount=DateUtils.overLappingDayCount(startDate1,endDate1,startDate2,endDate2);
System.out.println(dayCount);
}

还没有评论,来说两句吧...