Java 日期区间与日期区间集合的差集 代码实现

Java 日期区间与日期区间集合的差集 代码实现

  • 0. 解决思路
  • 1. 定义包含[开始日期~结束日期]的对象DateObject
  • 2. 初始化DateObject集合对象
  • 3. DateObject集合中的日期区间合并
  • 4. 已知日期区间`date`与日期区间集合`list`求交集
  • 5. 已知日期区间`date`再与交集`intersection`求差集`differences`
  • 6. 测试类

项目中遇到一个需求,就是过滤出一个日期区间与一个日期区间集合的差集。
例如:
已有日期区间:[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}]

0. 解决思路

  1. 测试数据准备
    1.1 已知日期区间对象 DateObject date
    1.2 初始化日期区间集合 List list
  2. 将日期集合list中的所有日期区间合并
  3. 已知日期区间datelist求交集(找出list中日期区间坐落到date的交集intersection
    Java 日期区间与日期区间集合的差集 代码实现_第1张图片
  4. 已知日期区间date再与交集intersection求差集differences
    Java 日期区间与日期区间集合的差集 代码实现_第2张图片

1. 定义包含[开始日期~结束日期]的对象DateObject

/**
 * 包含开始日期和结束日期的对象
 */
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 +  "}";
    }
}

2. 初始化DateObject集合对象

/**
  * 初始化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;
    }

3. DateObject集合中的日期区间合并

/**
 * 日期区间合并
 *
 * @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;
}

4. 已知日期区间date与日期区间集合list求交集

分析:集合中时间区间遍历与date相比较,两个时间区间会有4中相交的情况,此处只讨论有交集的情况。
Java 日期区间与日期区间集合的差集 代码实现_第3张图片

/**
* 求已知日期区间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;
}

5. 已知日期区间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;
}

6. 测试类

    @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"));
    }

你可能感兴趣的:(工具类)