背景描述
在公司进行人员描图模块开发时,涉及到了人员参会时长和参会次数的数据,比如一个人,两个月内开了14次会议。这里面就涉及到了,如果这个人参加的两个甚至多个会议有重叠的部分,这样的时间如何通过程序去进行合并处理。
思路
我们在程序中,可以将多个时间段中的两段分别“冒泡”比较,如果有重叠,那么进行合并,将这两个段去除,将合并后的时间段加入,得到的新的时间段的列表,重复上面的过程,直到没有重叠的时间段为止(递归
)
代码示例
- 定义一个类,类中有两个方法,getOverlapTime 和getTimeBucketList,
方法getOverlapTime:
public void getOverlapTime() throws ParseException {
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
List<TimeBucket> timeBucketList = new ArrayList<TimeBucket>();
timeBucketList.add(new TimeBucket("2019-10-29 13:30:00", "2019-10-29 16:30:00"));
timeBucketList.add(new TimeBucket("2019-10-29 13:30:00", "2019-10-29 17:30:00"));
timeBucketList.add(new TimeBucket("2019-10-30 14:30:00", "2019-10-30 17:30:00"));
timeBucketList.add(new TimeBucket("2019-10-30 15:30:00", "2019-10-30 18:30:00"));
timeBucketList.add(new TimeBucket("2019-10-30 16:30:00", "2019-10-30 19:30:00"));
List<TimeBucket> timeBucketList2 = getTimeBucketList(timeBucketList);
for (TimeBucket timeBucket : timeBucketList2) {
String format = dateFormat.format(timeBucket.getStart());
String format2 = dateFormat.format(timeBucket.getEnd());
System.out.println(format+" "+format2);
}
}
方法getTimeBucketList:
public List<TimeBucket> getTimeBucketList(List<TimeBucket> timeBucketList ) throws ParseException{
List<TimeBucket> myTimeBucketList = timeBucketList;
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Map<String, Integer> union = TimeBucket.union(myTimeBucketList);
if(union!=null) {
Integer i = union.get("i");
Integer j = union.get("j");
String start = null;
String end = null;
if(i.intValue()==j.intValue()) {//这条记录是多余的
TimeBucket timeBucket = myTimeBucketList.get(i);
myTimeBucketList.remove(timeBucket);
}else {
TimeBucket timeBucket = myTimeBucketList.get(i);
String startTime1 = dateFormat.format(timeBucket.getStart());
String endTime1 = dateFormat.format(timeBucket.getEnd());
TimeBucket timeBucket2 = myTimeBucketList.get(j);
String startTime2 = dateFormat.format(timeBucket2.getStart());
String endTime2 = dateFormat.format(timeBucket2.getEnd());
if(startTime1.compareTo(startTime2)<=0) {
start = startTime1;
}else {
start = startTime2;
}
if(endTime1.compareTo(endTime2)>=0) {
end = endTime1;
}else {
end = endTime2;
}
TimeBucket bucket = new TimeBucket(start,end);
myTimeBucketList.remove(timeBucket);
myTimeBucketList.remove(timeBucket2);
myTimeBucketList.add(bucket);
}
getTimeBucketList(myTimeBucketList);
}
return myTimeBucketList;
}
- getTimeBucketList方法接收的是一个时间段列表,返回的是一个不存在重复时间段的时间段列表,这里最关键的是TimeBucket类,这里有找出哪个重复的时间段,在myTimeBucketList里的角标
public class TimeBucket {
private static final ThreadLocal<DateFormat> FORMATS = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
private final Date start;
private final Date end;
public TimeBucket(Date start, Date end) {
if (start.after(end)) {
throw new IllegalArgumentException("时间段无效(开始日期需要小于结束日期)");
}
this.start = start;
this.end = end;
}
public TimeBucket(String start, String end) throws ParseException {
this(parse(start), parse(end));
}
public TimeBucket(long startTime, long endTime) {
this(new Date(startTime), new Date(endTime));
}
/**
* TimeBucket会返回重叠的时间段
* 若返回null说明没有重叠的时间段
*
* @param buckets 时间段
* @return
*/
public static Map<String, Integer> union(List<TimeBucket> buckets) {
List<Map<String, String>> list = new ArrayList<Map<String,String>>();
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//长度为1无需判断
if (buckets == null || buckets.size() <= 1) {
return null;
}
for (int i = 0; i < buckets.size() - 1; i++) {
String start = dateFormat.format(buckets.get(i).getStart());
String tempStart = start;
String end = dateFormat.format(buckets.get(i).getEnd());
String tempEnd = end;
for (int j = i + 1; j < buckets.size(); j++) {
String start2 = dateFormat.format(buckets.get(j).getStart());
String end2 = dateFormat.format(buckets.get(j).getEnd());
if (start.compareTo(start2)<0) {
start = start2;
}
if (end.compareTo(end2)>0) {
end = end2;
}
if (start.compareTo(end)<0) {
Map<String, Integer> map = new HashMap<String, Integer>();
map.put("i", i);
map.put("j", j);
return map;
}else {
start = tempStart;
end = tempEnd;
}
}
}
return null;
}
public Date getStart() {
return start;
}
public Date getEnd() {
return end;
}
public long getStartTime() {
return start.getTime();
}
public long getEndTime() {
return end.getTime();
}
private static Date parse(String str) throws ParseException {
return FORMATS.get().parse(str);
}
private static String format(Date str) {
return FORMATS.get().format(str);
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("start", format(start))
.add("end", format(end))
.toString();
}
}
对getTimeBucketList进行递归,每次都会合并重复的时间段,直到不需要进行合并,结束递归,进行返回,这样就可以获取到了不重复的时间段列表,遍历获取每个时间段的开始和结束时间,进行计算即可。