当前位置:网站首页>对周期内时间段是否重叠进行校验
对周期内时间段是否重叠进行校验
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,大家用的时候还是要进行详细的测试的。如果有任何问题,您都可以在评论区联系我。
边栏推荐
猜你喜欢
随机推荐
5个开源组件管理小技巧
进程(番外):自定义shell命令行解释器
Gartner 权威预测未来4年网络安全的8大发展趋势
激光驱鸟器
【详解】线程池及其自定义线程池的实现
【 LeetCode 】 design list
IDEA2021.2安装与配置(持续更新)
如何将 DevSecOps 引入企业?
剑指Offer 32.Ⅱ从上到下打印二叉树
增量编译技术在Lightly中的实践
408-二叉树-先序中序后序层次遍历
倒排单词
8款最佳实践,保护你的 IaC 安全!
v-model修饰符
install 命令
onvif/rtsp转gb28181协议,无缝对接国标平台
渗透测试(PenTest)基础指南
改变文件的扩展名
未来智安XDR入选《CCSIP 2022中国网络安全产业全景图》
【面试必看】链表的常见笔试题