import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
/**
* @description: 时间段实体类
* @author: myt
* @date: 11:16 2022/12/2
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class TimePeriod {
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date beginTime;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date endTime;
}
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.MapUtils;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
/**
* @description: 时间工具类 - 多个时间段取并集或交集
* @author: myt
* @date: 11:18 2022/12/2
*/
@Slf4j
public class TimeUtils {
/**
* 获取日期中的最大或最小者
* @param maxOrMin true 最大值 false最小值
* @param dates 可变参数
* @return 最大或最小的日期
*/
public static Date getExtremumDate(Boolean maxOrMin, Date... dates){
List<Date> dates1 = new ArrayList<>(dates.length);
for (Date date : dates){
if (date != null){
dates1.add(date);
}
}
if (dates1.size() == 0){
return null;
}
if (maxOrMin){
return Collections.max(dates1);
}else {
return Collections.min(dates1);
}
}
/**
* 多个时间段取并集或交集后的时间段列表
* @param mixedOrUnion true:交集 | false:并集
* @param periods 时间段列表
* @return 时间结果 map beginTime -> endTime
*/
public static Map<Date, Date> getTimePeriodsUnion(Boolean mixedOrUnion, List<TimePeriod> periods) {
periods.sort(Comparator.comparing(TimePeriod::getBeginTime));
Map<Date, Date> dateMap = new TreeMap<>();
for (TimePeriod period : periods) {
Date startTime = period.getBeginTime();
Date endTime = period.getEndTime();
if (MapUtils.isEmpty(dateMap)) {
dateMap.put(startTime, endTime);
}
Map<Date, Date> tempMap = new TreeMap<>();
//TreeMap能自动根据Key排序,只需要合并交集
//1.有交集则合并或取交集
//2.没有交集则添加
Iterator<Map.Entry<Date, Date>> iterator = dateMap.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<Date, Date> entry = iterator.next();
Date start = entry.getKey();
Date end = entry.getValue();
//两个时间段 [A, B)、[X, Y),X < B && A < Y 或者 A < Y && X < B则有交集
if ((startTime.before(end) && endTime.after(start)) || (start.before(endTime) && end.after(startTime))){
iterator.remove();
if (mixedOrUnion){
tempMap.put(TimeUtils.getExtremumDate(true,startTime,start),TimeUtils.getExtremumDate(false,endTime,end));
}else {
tempMap.put(TimeUtils.getExtremumDate(false,startTime,start),TimeUtils.getExtremumDate(true,endTime,end));
}
}else{
if (!iterator.hasNext()){
tempMap.put(startTime, endTime);
}
}
}
dateMap.putAll(tempMap);
}
return dateMap;
}
/**
* @description: String 转 Date
*
* @param s:
* @author: myt
* @date: 11:43 2022/12/2
* @return: {@link Date}
*/
public static Date transferString2Date(String s) {
Date date = new Date();
try {
date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(s);
} catch (ParseException e) {
log.error("时间转换错误, string = {}", s, e.getMessage());
}
return date;
}
/**
* @description: Date 转 String
*
* @param date:
* @author: myt
* @date: 12:01 2022/12/2
* @return: {@link String}
*/
public static String transferDate2String(Date date) {
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date);
}
public static void main(String[] args) {
// 测试数据
List<TimePeriod> list = new ArrayList<>();
list.add(new TimePeriod(transferString2Date("2022-01-12 08:01:07"),transferString2Date("2022-01-16 08:41:08")));
list.add(new TimePeriod(transferString2Date("2022-01-14 10:52:36"),transferString2Date("2022-02-17 08:51:22")));
list.add(new TimePeriod(transferString2Date("2022-01-15 10:52:48"),transferString2Date("2022-01-20 08:19:00")));
list.add(new TimePeriod(transferString2Date("2022-01-01 09:51:39"),transferString2Date("2022-06-17 09:53:01")));
//求交集
Map<Date, Date> dateMap1 = TimeUtils.getTimePeriodsUnion(true, list);
for (Map.Entry<Date, Date> entry : dateMap1.entrySet()) {
System.out.println("交集开始时间:" + transferDate2String(entry.getKey()) + " 交集结束时间:" + transferDate2String(entry.getValue()));
}
System.out.println("=====================================================================");
//求并集
Map<Date, Date> dateMap2 = TimeUtils.getTimePeriodsUnion(false, list);
for (Map.Entry<Date, Date> entry : dateMap2.entrySet()) {
System.out.println("并集开始时间:" + transferDate2String(entry.getKey()) + " 并集结束时间:" + transferDate2String(entry.getValue()));
}
}
}