项目中遇到一个需求,就是过滤出一个日期区间与一个日期区间集合的差集。
例如:
已有日期区间:[2019-07-01~2019-07-31]
日期区间集合为:[{2019-07-01, 2019-07-10}, {2019-07-15, 2019-07-20}, {2019-07-22, 2019-07-25}]
目标结果:[{2019-07-11, 2019-07-14}, {2019-07-21, 2019-07-21}, {2019-07-26, 2019-07-31}]
/**
* 包含开始日期和结束日期的对象
*/
public class DateObject {
private Date startDate;
private Date endDate;
public DateObject(Date startDate, Date endDate) {
this.startDate = startDate;
this.endDate = endDate;
}
public Date getStartDate() {
return startDate;
}
public void setStartDate(Date startDate) {
this.startDate = startDate;
}
public Date getEndDate() {
return endDate;
}
public void setEndDate(Date endDate) {
this.endDate = endDate;
}
@Override
public String toString() {
return "DateObject{startDate=" + startDate + ", endDate=" + endDate + "}";
}
}
/**
* 初始化DateObject集合对象
*
* @return
* @throws Exception
*/
public List init() throws Exception {
List list = Lists.newArrayList();
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
list.add(new DateObject(format.parse("2019-07-01"), format.parse("2019-07-10")));
list.add(new DateObject(format.parse("2019-07-15"), format.parse("2019-07-20")));
list.add(new DateObject(format.parse("2019-07-22"), format.parse("2019-07-25")));
// 排序,默认日期正序
list.sort(Comparator.comparing(DateObject::getStartDate));
return list;
}
/**
* 日期区间合并
*
* @param list
* @return
* @throws Exception
*/
public List merge(List list) throws Exception {
if (list == null || list.size() == 0) {
return new ArrayList<>();
}
List result = new ArrayList<>();
DateObject first = list.get(0);
for (int i = 1; i < list.size(); i++) {
DateObject next = list.get(i);
// 判断first与next是否有交集
if (next.getStartDate().getTime() >= first.getStartDate().getTime()
&& next.getStartDate().getTime() <= first.getEndDate().getTime()) {
// 合并区间
first.setEndDate(new Date(Math.max(first.getEndDate().getTime(), next.getEndDate().getTime())));
} else {
// 没有交集,直接添加
result.add(first);
first = next;
}
}
result.add(first);
return result;
}
date
与日期区间集合list
求交集/**
* 求已知日期区间date与日期区间集合list的交集
*
* @param dateObject
* @param list
* @return 交集
*/
public List intersection(DateObject dateObject, List list) {
List result = new ArrayList<>();
for (DateObject date : list) {
// dateObject全部在date时间区间内:date.startDate <= dateObject.startDate < dateObject.endDate <= date.endDate
// 则dateObject与list的交集为空
if (date.getStartDate().getTime() <= dateObject.getStartDate().getTime()
&& date.getEndDate().getTime() >= dateObject.getEndDate().getTime()) {
result = Lists.newArrayList();
break;
}
// date全部在dateObject时间区间内:dateObject.startDate <= date.startDate < date.endDate <= dateObject.endDate
// 则交集为[date.startDate, date.endDate]
else if (date.getStartDate().getTime() >= dateObject.getStartDate().getTime()
&& date.getEndDate().getTime() <= dateObject.getEndDate().getTime()) {
result.add(new DateObject(date.getStartDate(), date.getEndDate()));
}
// date结束时间在dateObject区间内:date.startDate <= dateObject.startDate <= date.endDate <= dateObject.endDate
// 则交集为[dateObject.startDate, date.endDate]
else if (date.getStartDate().getTime() <= dateObject.getStartDate().getTime()
&& date.getEndDate().getTime() >= dateObject.getStartDate().getTime()
&& date.getEndDate().getTime() <= dateObject.getEndDate().getTime()) {
result.add(new DateObject(dateObject.getStartDate(), date.getEndDate()));
}
// date开始时间在dateObject内:dateObject.startDate <= date.startDate <= dateObject.endDate <= date.endDate
// 则交集为[date.startDate, dateObject.endDate]
else if (date.getEndDate().getTime() > dateObject.getEndDate().getTime()) {
result.add(new DateObject(date.getStartDate(), dateObject.getEndDate()));
}
}
return result;
}
date
再与交集intersection
求差集differences
集合intersection中的日期区间已经排好序了,第一个元素的结束日期与下一个元素的开始日期就是要的结果,以此类推
/**
* 求差集
*
* @param dateObject
* @param list
* @return
*/
private List differences(DateObject dateObject, List list) {
List result = new ArrayList<>();
DateObject first = list.get(0);
if (list.size() == 1) {
result.add(new DateObject(first.getEndDate(), dateObject.getEndDate()));
} else {
for (int i = 1; i < list.size(); i++) {
DateObject next = list.get(i);
result.add(new DateObject(first.getEndDate(), next.getStartDate(), -1)));
first = next;
}
DateObject last = list.get(list.size() - 1);
result.add(new DateObject(last.getEndDate(), dateObject.getEndDate()));
}
return result;
}
@Test
public void test1() throws Exception {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
DateObject open = new DateObject(format.parse("2019-07-01"), format.parse("2019-07-31"));
// 时间区间合并
List merge = merge(init());
System.out.println("时间区间合并:" + JSONObject.toJSONStringWithDateFormat(merge, "yyyy-MM-dd HH:mm:ss"));
// 求交集
List result = intersection(open, merge);
System.out.println("交集:" + JSONObject.toJSONStringWithDateFormat(result, "yyyy-MM-dd"));
// 求差集
List list = differences(open, result);
System.out.println("差集:" + JSONObject.toJSONStringWithDateFormat(list, "yyyy-MM-dd HH:mm:ss"));
}