时间段由开始时间和结束时间组成,本工具类可以对时间段列表进行取并集,取交集,取差集,也可以返回单个时间点位于时间段列表中的位置。时间段的开始结束时间放在Date[]里 Date[0]表示开始时间,Date[1]表示结束时间。
import cn.hutool.core.date.DateUtil;
import java.text.ParseException;
import java.util.*;
/**
* 时间段处理工具类
* 用于进行时间段的合并(加法)/时间段的剔除(减法)/时间段的取交集,及单个时间点位于时间段内的位置。
*/
public class TimePeriodUtils {
/**
* 合并时间段集合
*
* @param timePeriods 时间段集合
* @return 合并后的时间段集合
*/
private static List<Date[]> mergeTimePeriods(List<Date[]> timePeriods) {
if (timePeriods == null || timePeriods.isEmpty()) {
return new ArrayList<>();
}
List<Date[]> resultList = new ArrayList<>();
// 对时间段集合按开始时间排序
Collections.sort(timePeriods, Comparator.comparing(Date -> Date[0]));
Date[] timePeriod = timePeriods.get(0);
for (int i = 1; i < timePeriods.size(); i++) {
Date[] nextTimePeriod = timePeriods.get(i);
if (nextTimePeriod[0].compareTo(timePeriod[1]) <= 0) {
// 有交集,合并时间段
timePeriod[1] = nextTimePeriod[1].compareTo(timePeriod[1]) > 0 ? nextTimePeriod[1] : timePeriod[1];
} else {
// 无交集,加入结果集
resultList.add(timePeriod);
timePeriod = nextTimePeriod;
}
}
resultList.add(timePeriod);
return resultList;
}
/**
* 该函数接受两个参数:timePeriods和deleteTimePeriods。它遍历timePeriods中的每个时间段,
* 对于每个时间段,检查它是否与任何deleteTimePeriods时间段重叠。如果重叠,它将时间段拆分为两部分,
* 并将不重叠的部分添加到resultList中。
* 最后,它返回resultList,其中包含减去deleteTimePeriods时间段后的所有时间段。
*
* @param timePeriods
* @param deleteTimePeriods
* @return
*/
public static List<Date[]> subtractTimePeriods(List<Date[]> timePeriods, List<Date[]> deleteTimePeriods) {
// 创建一个列表来存储timePeriods和deleteTimePeriods之间的差异
ArrayList<Date[]> resultList = new ArrayList<>();
for (Date[] dateRange : timePeriods) {
boolean isOverlap = false;
for (Date[] deleteRange : deleteTimePeriods) {
if (dateRange[0].before(deleteRange[1]) && deleteRange[0].before(dateRange[1])) {
// 如果两个时间段重叠,则将时间段拆分为两个部分
if (dateRange[0].before(deleteRange[0])) {
resultList.add(new Date[]{dateRange[0], deleteRange[0]});
}
if (dateRange[1].after(deleteRange[1])) {
resultList.add(new Date[]{deleteRange[1], dateRange[1]});
}
isOverlap = true;
break;
}
}
if (!isOverlap) {
// 如果时间段与任何deleteTimePeriods时间段不重叠,则将其添加到resultList中
resultList.add(dateRange);
}
}
return resultList;
}
/**
* 该函数接受两个参数:timePeriods和datePoint。它遍历timePeriods中的每个时间段,
* 如果datePoint在该时间段内,则返回该时间段的开始和结束时间以及结果类型1。
* 如果datePoint不在任何时间段内,则它将遍历时间段以找到在datePoint时间点之前的最大结束时间和在datePoint时间点之后的最小开始时间,并返回这些时间以及结果类型2。
* 如果timePeriods列表为空,则它将返回null和结果类型-1。
*
* @param timePeriods 时间段集合
* @param datePoint 时间点 该时间点需要加个一秒钟以避免与端点重合引起bug
* @return 位置信息数组
*/
public static Object[] getTimePeriodPosition(List<Date[]> timePeriods, Date datePoint) {
for (Date[] timePeriod : timePeriods) {
// 如果datePoint在timePeriod范围内,则返回开始和结束时间以及结果类型1
if (timePeriod[0].before(datePoint) && timePeriod[1].after(datePoint)) {
return new Object[]{1, timePeriod[0], timePeriod[1]};
}
}
Date maxEndTime = null;
Date minStartTime = null;
for (Date[] timePeriod : timePeriods) {
// 如果datePoint在timePeriod之前,则更新最大结束时间
if (timePeriod[1].before(datePoint) && (maxEndTime == null || timePeriod[1].after(maxEndTime))) {
maxEndTime = timePeriod[1];
}
// 如果datePoint在timePeriod之后,则更新最小开始时间
else if (timePeriod[0].after(datePoint) && (minStartTime == null || timePeriod[0].before(minStartTime))) {
minStartTime = timePeriod[0];
}
}
// 如果最大结束时间和最小开始时间都为空,则说明timePeriods列表为空
if (maxEndTime == null && minStartTime == null) {
return new Object[]{-1, null, null};
}
// 如果最大结束时间为空,则说明datePoint在所有时间段之后,返回最小开始时间和结果类型2
if (maxEndTime == null) {
return new Object[]{2, null, minStartTime};
}
// 如果最小开始时间为空,则说明datePoint在所有时间段之前,返回最大结束时间和结果类型2
if (minStartTime == null) {
return new Object[]{2, maxEndTime, null};
}
// 如果最大结束时间和最小开始时间都不为空,则返回它们以及结果类型2
return new Object[]{2, maxEndTime, minStartTime};
}
/**
* 时间段取交集
* 该函数首先判断输入参数 timePeriods 是否为空,如果为空则返回 null。接下来遍历 timePeriods,
* 从第一个时间段开始,不断更新已合并的时间段的起始时间和结束时间。
* 如果当前时间段和已合并的时间段没有交集,则返回空数组。如果所有时间段都被合并,最终返回合并后的时间段。
* @param timePeriods
* @return
*/
public static Date[] concentrateTimePeriods(List<Date[]> timePeriods) {
if (timePeriods == null || timePeriods.size() == 0) {
return null;
}
Date start = timePeriods.get(0)[0];
Date end = timePeriods.get(0)[1];
for (int i = 1; i < timePeriods.size(); i++) {
Date[] period = timePeriods.get(i);
if (period[0].after(end) || period[1].before(start)) {
// 当前时间段和已合并的时间段没有交集,返回空数组
return new Date[0];
}
start = period[0].after(start) ? period[0] : start;
end = period[1].before(end) ? period[1] : end;
}
return new Date[]{start, end};
}
/**
* 主函数,用于测试
*/
public static void main(String[] args) throws ParseException {
// SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// // 初始化时间段集合
// Date[] date1 = {sdf.parse("2023-02-10 09:00:00"), sdf.parse("2023-02-10 10:00:00")};
// Date[] date2 = {sdf.parse("2023-02-10 10:00:00"), sdf.parse("2023-02-10 12:00:00")};
// Date[] date3 = {sdf.parse("2023-02-10 08:00:00"), sdf.parse("2023-02-10 13:00:00")};
// List<Date[]> timePeriods = new ArrayList<>();
// timePeriods.add(date1);
// timePeriods.add(date2);
// timePeriods.add(date3);
// List<Date[]> result1 = mergeTimePeriods(timePeriods);
// printResult(result1);
// System.out.println("-------------------------------");
// // 初始化删除时间段集合
// Date[] deleteDate1 = {sdf.parse("2023-02-10 09:00:00"), sdf.parse("2023-02-10 12:00:00")};
// List<Date[]> deleteTimePeriods = new ArrayList<>();
// deleteTimePeriods.add(deleteDate1);
//
// List<Date[]> result2 = subtractTimePeriods(result1, deleteTimePeriods);
// printResult(result2);
// // 调用函数
// Object[] result = getTimePeriodPosition(subtractTimePeriods(mergeTimePeriods(timePeriods), deleteTimePeriods), sdf.parse("2023-02-10 08:00:01"));
// // 打印结果
// System.out.println("-------------------------------");
// System.out.println(Arrays.toString(result));
//------------------------------------------
// SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// List<Date[]> timePeriods = new ArrayList<>();
// timePeriods.add(new Date[] { sdf.parse("2022-02-13 02:00:00"), sdf.parse("2022-02-13 12:00:00") });
// timePeriods.add(new Date[] { sdf.parse("2022-02-13 01:00:00"), sdf.parse("2022-02-13 11:00:00") });
// timePeriods.add(new Date[] { sdf.parse("2022-02-13 00:00:00"), sdf.parse("2022-02-13 10:00:00") });
//
// Date[] result = concentrateTimePeriods(timePeriods);
//
// System.out.println("原始时间段:");
// for (Date[] period : timePeriods) {
// System.out.println(sdf.format(period[0]) + " - " + sdf.format(period[1]));
// }
//
// System.out.println("合成时间段:");
// System.out.println(sdf.format(result[0]) + " - " + sdf.format(result[1]));
}
private static void printResult(List<Date[]> result) {
for (int i = 0; i < result.size(); i++) {
Date[] item = result.get(i);
System.out.println(DateUtil.formatDateTime(item[0]) + "--->" + DateUtil.formatDateTime(item[1]));
}
}
}