背景描述
在公司進行人員描圖模塊開發時,涉及到了人員參會時長和參會次數的數據,比如一個人,兩個月內開了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進行遞歸,每次都會合並重復的時間段,直到不需要進行合併,結束遞歸,進行返回,這樣就可以獲取到了不重複的時間段列表,遍歷獲取每個時間段的開始和結束時間,進行計算即可。