最近在做一个功能,需要统计请假天数,按月统计。而实际的请假数据就包括跨月的情况,所以就出现一个这样的问题。要计算本月内的请假天数。实际上就是求两个时间段内的重复天数。
大概有三种思路:
一、常规思路
以程序员的常规思维来看,计算两个时间段内的重复天数,分为多种情况。包括 包含、相交、相离 另外还需要处理边界值。每种情况又有细分,比如包含,如果是请假范围包含月份范围,则取月份范围。如果月份范围包括请假范围,则直接取请假范围。这样一看,逻辑思考上就较为复杂,写出来的代码阅读性就不高,容易出现纰露。
二、非常规思路
再来看看非常规思路,第一种的缺点是逻辑较为复杂,容易出漏洞。那有没有逻辑简单的方法呢?其实我们可以这样,将月份范围内的所有日期全部放到一个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); }
还没有评论,来说两句吧...