当前位置:网站首页>对周期内时间段是否重叠进行校验

对周期内时间段是否重叠进行校验

2022-08-02 03:35:00 abments

 

目录

前言

一、核心思想

二、实现代码

三、测试用例

总结



前言

写这个小功能的背景:在开发中会遇到对周期内时间是否发生重叠进行校验的情况,如果只是对某一天的多个时间端进行校验相对来说还好多些,如果是周期内不连续的多个时间段校验,就有点复杂了(至少在我看来是这样)。具体的需要可以用下图表示:


一、核心思想

对于这个功能,我采用了二维数组的方式去存储时间段数据,第二层数组存放的是单条时间周期也就是上图中每一行的数据,如果某一天没有被设置时间就不用赋值,具体代码实现可以参考init()方法。进行时间比对时,对应值比对对应一天所代表的数据,具体代码实现可以参checkTimeInfo()方法。

二、实现代码

完整代码如下:

import java.util.List;
import java.util.Objects;

/**
 * 校验多个周期性时间是否存在时间重叠
 * 以天为单位,把设置的时间存放到当天对应的数组中,通过比对相同位置的数据时间是否重叠判断周期内时间是否重叠
 * exmp:
 * 1.每周二到周四的14:00-15:00 存入数组 [],[14:00-15:00],[14:00-15:00],[14:00-15:00][],[],[]
 * 2.每周三到周五的 14:30-16:00 存入数组[],[],[14:30-16:00],[14:30-16:00],[14:30-16:00],[],[]
 */
public class CycleTimeValidate {

    /**
     * 每日,每周,每月
     * 两种或两种以上元素同时存在,可能出现时间交叉的情况
     * 统一设置容器大小为31
     * 类型 时间
     */
    private CycleType cycleType;

    /**
     * pair 左边为开始时间,右边为结束时间
     */
    private List<TimeInfo> timeInfoList;

    private TimeInfo[][] timeInfoArray;

    /**
     * [0:10-1:20],[0:10-1:20],[0:10-1:20],[],[],[],[]
     * [1:00-1:40],[1:00-1:40],[],[],[],[],[]
     * 先拿第一组数据与其他组数据中对应时间进行比较,判断时间是否存在交叉情况
     * (前者开始时间大于后者开始时间,且小于后者结束时间,或前者结束时间大于后者开始时间且小于开始时间)
     * <p>
     * 依次比较其他组数据
     *
     * @param cycleType 周期类型
     * @param timeInfoList 时间列表
     */
    public CycleTimeValidate(CycleType cycleType, List<TimeInfo> timeInfoList) {
        this.cycleType = cycleType;
        this.timeInfoList = timeInfoList;
        init();
    }

    private void init() {
        timeInfoArray = new TimeInfo[timeInfoList.size()][];
        for (int i = 0; i < timeInfoList.size(); i++) {
            TimeInfo timeInfo = timeInfoList.get(i);
            if (CycleType.EVERY_DAY.equals(cycleType)) {
                timeInfoArray[i] = new TimeInfo[]{timeInfo};
            } else {
                TimeInfo[] nestTimeInfo = new TimeInfo[CycleType.EVERY_WEEK.num];
                for (int j = 0; j < CycleType.EVERY_WEEK.num; j++) {
                    if (timeInfo.dayInRange(j + 1)) {
                        nestTimeInfo[j] = timeInfo;
                    }
                }
                timeInfoArray[i] = nestTimeInfo;
            }
        }
    }

    /**
     * 校验时间是否重叠
     * @return true:不重叠 false:重叠
     */
    public boolean checkTimeInfo() {

        for (int i = 0; i < timeInfoArray.length - 1; i++) {
            TimeInfo[] timeInfos = timeInfoArray[i];
            //纵向校验,当前组数据对应的时间与其他组数据对应的时间比较
            for (int num = 0; num < cycleType.num; num++) {
                TimeInfo timeInfo = timeInfos[num];
                if (Objects.isNull(timeInfo)) continue;
                for (int j = i + 1; j < timeInfoArray.length; j++) {
                    TimeInfo[] anotherTimeInfos = timeInfoArray[j];
                    if (timeInfo.timeIsCrossAnother(anotherTimeInfos[num])) return false;
                }
            }
        }
        return true;
    }

    public static class TimeInfo {
        /**
         * 开始日期,note 数字应该大于0
         * 例如:2
         */
        private int startDay;
        /**
         * 结束日期,note 数字应该大于0
         * 例如:5
         */
        private int endDay;
        /**
         * 开始时间
         * 例如:10:00
         */
        private String startTime;

        /**
         * 开始时间镜像值,方便计算时间的前后顺序
         * 10:00 --->>> 1000
         */
        private int startTimeMir;

        /**
         * 结束时间
         * 例如:14:30
         */
        private String endTime;

        private int endTimeMir;

        public TimeInfo(String startTime, String endTime) throws Exception {
            this.startTime = startTime;
            this.endTime = endTime;
            init();
        }

        public TimeInfo(int startDay, int endDay, String startTime, String endTime) throws Exception {
            if (startDay < 1 || endDay < 1) {
                startDay = 1;
                endDay = 1;
            }
            this.startDay = startDay;
            this.endDay = endDay;
            this.startTime = startTime;
            this.endTime = endTime;
            init();
        }

        private void init() throws Exception {
            startTimeMir = getTimeMir(startTime);
            endTimeMir = getTimeMir(endTime);
            if (!timeStartBeforeEnd() || !dayStartBeforeEnd()) throw new Exception("开始时间不能大于结束时间");
        }

        /**
         * 时间是否存在交叉
         * 1.前者开始时间大于后者开始时间,且小于后者结束时间,
         * 或
         * 2.前者结束时间大于后者开始时间,且小于后者结束时间
         *或
         * 3.前者开始时间小于后者开始时间,且前者结束时间大于后者结束时间
         * @param anotherTimeInfo 需要比对的时间信息
         * @return true:存在交叉情况  false 不存在交叉情况
         */
        private boolean timeIsCrossAnother(TimeInfo anotherTimeInfo) {

            if (Objects.isNull(anotherTimeInfo)) return false;

            boolean b1 = (this.startTimeMir > anotherTimeInfo.startTimeMir) && (this.startTimeMir < anotherTimeInfo.endTimeMir);
            if (b1) {
                return true;
            }

            boolean b2 = (this.endTimeMir > anotherTimeInfo.startTimeMir) && (this.endTimeMir < anotherTimeInfo.endTimeMir);
            if (b2){
                return true;
            }

            return (this.startTimeMir<anotherTimeInfo.startTimeMir) && (this.endTimeMir >anotherTimeInfo.endTimeMir);

        }

        private int getTimeMir(String time) throws Exception {
            String[] split = time.split(":");
            if (split.length != 3) {
                throw new Exception("时间格式有误!需要的格式为HH:MM:ss");
            }
            if (split[1].length() !=2 || split[2].length() != 2){
                throw new Exception("时间格式有误!需要的格式为HH:MM:ss");
            }
            return Integer.valueOf(split[0] + split[1] + split[2]);
        }

        private boolean dayInRange(int day) {
            return day - startDay >= 0 && endDay - day >= 0;
        }

        private boolean dayStartBeforeEnd() {
            return startDay - endDay <= 0;
        }

        private boolean timeStartBeforeEnd() {
            return this.startTimeMir <= this.endTimeMir;
        }

        public int getStartDay() {
            return startDay;
        }

        public void setStartDay(int startDay) {
            this.startDay = startDay;
        }

        public int getEndDay() {
            return endDay;
        }

        public void setEndDay(int endDay) {
            this.endDay = endDay;
        }

        public String getStartTime() {
            return startTime;
        }

        public void setStartTime(String startTime) {
            this.startTime = startTime;
        }

        public String getEndTime() {
            return endTime;
        }

        public void setEndTime(String endTime) {
            this.endTime = endTime;
        }
    }

    public enum CycleType {

        /**
         * 每天
         */
        EVERY_DAY(1),
        /**
         * 每周
         */
        EVERY_WEEK(7),
        /**
         * 每月
         */
        EVERY_MONTH(30);

        int num;

        CycleType(int num) {
            this.num = num;
        }
    }
}

 说明:为了避免出现过多的类,且保持良好的封装效果,上面的代码采用了一些内部类,如果有需要同学们可以把它们拆开来用。我个人认为CycleType 枚举类和 TimeInfo 类的使用在一定程度上简化了核心代码。

三、测试用例

完整测试代码如下:

 public static void main(String[] args) throws Exception {

        List<CycleTimeValidate.TimeInfo> timeInfoList = new ArrayList<>();
        //后者开始时间在前者时间范围
        CycleTimeValidate.TimeInfo timeInfo = new CycleTimeValidate.TimeInfo(1, 3, "0:10:00", "1:20:00");
        CycleTimeValidate.TimeInfo timeInfo1 = new CycleTimeValidate.TimeInfo(2, 4, "0:15:00", "1:40:00");
       /* timeInfoList.add(timeInfo);
        timeInfoList.add(timeInfo1);*/

        //后者结束时间在前者时间范围
        CycleTimeValidate.TimeInfo timeInfo2 = new CycleTimeValidate.TimeInfo(1, 3, "0:10:00", "1:20:00");
        CycleTimeValidate.TimeInfo timeInfo3 = new CycleTimeValidate.TimeInfo(2, 4, "0:05:00", "1:15:00");
        /*timeInfoList.add(timeInfo2);
        timeInfoList.add(timeInfo3);*/

        //后者开始时间和结束时间都在前者时间范围
        CycleTimeValidate.TimeInfo timeInfo4 = new CycleTimeValidate.TimeInfo(1, 3, "0:10:00", "1:20:00");
        CycleTimeValidate.TimeInfo timeInfo5 = new CycleTimeValidate.TimeInfo(2, 4, "0:15:00", "1:18:00");
     /*   timeInfoList.add(timeInfo4);
        timeInfoList.add(timeInfo5);*/

        //后者开始时间和结束时间都不在前者时间范围
        CycleTimeValidate.TimeInfo timeInfo6 = new CycleTimeValidate.TimeInfo(1, 3, "0:10:00", "1:20:00");
        CycleTimeValidate.TimeInfo timeInfo7 = new CycleTimeValidate.TimeInfo(2, 4, "1:40:00", "2:40:00");
/*        timeInfoList.add(timeInfo6);
        timeInfoList.add(timeInfo7);*/

        CycleTimeValidate.TimeInfo timeInfo8 = new CycleTimeValidate.TimeInfo(1, 3, "0:10:00", "1:20:00");
        CycleTimeValidate.TimeInfo timeInfo9 = new CycleTimeValidate.TimeInfo(2, 4, "1:30:00", "2:40:00");
        CycleTimeValidate.TimeInfo timeInfo10 = new CycleTimeValidate.TimeInfo(5, 7, "3:15:00", "4:18:00");
        timeInfoList.add(timeInfo8);
        timeInfoList.add(timeInfo9);
        timeInfoList.add(timeInfo10);


        CycleTimeValidate cycleTimeValidateTest = new CycleTimeValidate(CycleTimeValidate.CycleType.EVERY_DAY, timeInfoList);

        System.out.println(cycleTimeValidateTest.checkTimeInfo());
    }

总结

总体实现就是这个样子的,希望这个小功能能够帮助到有需要的同学吧。另外需要说明的是我并不能保证代码没有bug,大家用的时候还是要进行详细的测试的。如果有任何问题,您都可以在评论区联系我。

原网站

版权声明
本文为[abments]所创,转载请带上原文链接,感谢
https://blog.csdn.net/abments/article/details/125828786