【问题标题】:Given Two lists of date ranges, how to find the non-overlapping dates in java给定两个日期范围列表,如何在java中找到不重叠的日期
【发布时间】:2018-12-11 06:43:45
【问题描述】:

我不确定我的标题是否正确,但这就是我想要实现的目标。 考虑以下两个类,AbsentPeriod、UnavailablePeriod。

class AbsentPeriod
{
    Date startDate;
    Date endDate;
}

class UnavailablePeriod
{
    Date startDate;
    Date endDate;
}

给定

Date StartDate // starting point
Date EndDate //ending point
List<AbsentPeriod> absentperiods
List<UnavailablePeriods> unavailablePeriods

寻找

List<AvailablePeriod> 

其开始日期和结束日期的日期不与缺席和不可用期间的日期重叠;在给定的 StartDate 和 endDate 之间

class AvailablePeriod
{
   Date startDate;
   Date endDate;
}

【问题讨论】:

  • 到目前为止你尝试了什么?
  • 好吧,虽然它使用 JodaTime,但它应该可以轻松转换为 Java 日期/时间 API - for example
  • “句号”是句号,句号(对不起)——虽然在你的例子中它增加了一些可能的澄清,但尽量避免创建代表相同概念但为特定目的命名的数据类型,这就是为什么你有变量名的原因;) - 我可能会想用RangeSpan 代替,因为“句号”似乎反映了一个点
  • 范围是日期范围还是整数范围、浮点范围还是字符范围都没有关系,不是吗?

标签: java date datetime overlap


【解决方案1】:

如果我的理解成立:当有一些 类似缺席的 期间列表时,您正试图找出所有 可用 期间

那么当有很多absent-like时期列表时,有一个完整的解决方案可以解决:

public class Extra_1_interval_merge {
    @Test
    public void testAvailablePeriod() {
        List<MyPeriod> absentPeriods0 = new ArrayList<>();
        absentPeriods0.add(makePeriod(LocalDate.now(), LocalDate.now().plusDays(1), PeriodType.ABSENT));
        absentPeriods0.add(makePeriod(LocalDate.now().plusDays(4), LocalDate.now().plusDays(6), PeriodType.ABSENT));
        absentPeriods0.add(makePeriod(LocalDate.now().plusDays(2), LocalDate.now().plusDays(3), PeriodType.ABSENT));


        List<MyPeriod> absentPeriods1 = new ArrayList<>();
        absentPeriods1.add(makePeriod(LocalDate.now(), LocalDate.now().plusDays(2), PeriodType.UNAVAILABLE));
        absentPeriods1.add(makePeriod(LocalDate.now().plusDays(5), LocalDate.now().plusDays(7), PeriodType.UNAVAILABLE));

        List<List<MyPeriod>> absentListList = new ArrayList<>();
        absentListList.add(absentPeriods0);
        absentListList.add(absentPeriods1);
        System.out.println(getAvailablePeriods(absentListList));
    }

    private List<MyPeriod> getAvailablePeriods(List<List<MyPeriod>> absentListList) {
        // Step - 1: Collect all periods;
        List<MyPeriod> tempList = new ArrayList<>();
        absentListList.stream().forEach(list -> tempList.addAll(list));

        // Step - 2: Sort the periods based on the startDate and then endDate;
        List<MyPeriod> absentList = tempList.stream().sorted((period1, period2) -> {
            if (!period1.startDate.isEqual(period2.startDate)) {
                return period1.startDate.compareTo(period2.startDate);
            } else {
                return period1.endDate.compareTo(period2.endDate);
            }
        }).collect(toList());

        // Step - 3: Merge all overlapped periods to form an one-dimension occupied period list;
        List<MyPeriod> mergedPeriods = new ArrayList<>();
        for (MyPeriod period : absentList) {
            if (mergedPeriods.isEmpty()) {
                mergedPeriods.add(period);
            } else {
                MyPeriod lastPeriod = mergedPeriods.get(mergedPeriods.size() - 1);
                if (!lastPeriod.endDate.isBefore(period.startDate)) {
                    if (lastPeriod.endDate.isBefore(period.endDate)) {
                        lastPeriod.endDate = period.endDate;
                    }
                } else {
                    mergedPeriods.add(period);
                }
            }
        }

        // Step - 4: Pick the periods from the occupied period list;
        List<MyPeriod> availablePeriods = new ArrayList<>();
        for (int i = 0, len = mergedPeriods.size(); i < len - 1; i++) {
            availablePeriods.add(makePeriod(mergedPeriods.get(i).endDate, mergedPeriods.get(i + 1).startDate, PeriodType.AVAILABLE));
        }
        return availablePeriods;
    }

    private MyPeriod makePeriod(LocalDate startDate, LocalDate endDate, PeriodType periodType) {
        MyPeriod thePeriod = null;
        switch (periodType) {
            case ABSENT:
                thePeriod = new AbsentPeriod();
                break;
            case UNAVAILABLE:
                thePeriod = new UnavailablePeriod();
                break;
            case AVAILABLE:
                thePeriod = new AvailablePeriod();
                break;
            default:
                thePeriod = new MyPeriod();
                break;
        }
        thePeriod.startDate = startDate;
        thePeriod.endDate = endDate;
        return thePeriod;
    }

    enum PeriodType {
        ABSENT,
        UNAVAILABLE,
        AVAILABLE;
    }

    class MyPeriod {
        LocalDate startDate;
        LocalDate endDate;

        @Override
        public String toString() {
            return String.format("Start: %s, End: %s", startDate, endDate);
        }
    }

    class AbsentPeriod extends MyPeriod {
    }

    class UnavailablePeriod extends MyPeriod {
    }

    class AvailablePeriod extends MyPeriod {
    }

}

对于输入:

  • 缺席期间列表 - 1: [0, 1], [4, 6], [2, 3]
  • 缺席期间列表 - 2: [0, 2], [5, 7]

最终结果将是:

  • 可用周期列表:[3, 4]

如果需要,您可以尝试更多缺席期间列表。

更新

我不知道为什么 OP 在这里需要三种不同类型的Period/Interval。但是为了解决具体问题,我根据OP的需要更新了解决方案。

正如其他 cmets 指出的那样,为什么有三种不同的类型?我不知道...

【讨论】:

  • 真的。这就是我被困在类似缺席的时期的地方。明天试试这个。看起来它可以工作。
  • 有什么困惑吗?如果没有,请接受它作为答案。
  • 这里你使用的是单个类 MyPeriod,但我有三个不同的类,虽然开始日期和结束日期的内容相同,但我们需要用 AbsentPeriod、UnavailablePeriod 和 AvailablePeriod 来区分它们。
  • @Vinay 不,你没有,不是真的。您只需要一个“日期范围”对象,它可以分配给一系列容器/List,这将区分它们 - 如果“真的”需要,我可能会使用“类型”标识符或创建一系列“接口”可以用来按类型“区分”类,但那就是我。话虽如此,没有一个单一的答案可以满足您的所有需求 - 您将从多种不同的解决方案中汲取概念和想法,或者自己制作,这是优秀开发人员的标志
  • @Vinay 你是……哈哈,我刚睡醒就看到了 MadProgramer 的回复。你……(让他不高兴……哈哈)我会进一步更新解决方案。完全不知道为什么您需要 不同的 类型的解决方案。
【解决方案2】:

您可以遍历AbsentPeriod & UnavailablePeriod 的列表,使用以下函数检查日期是否重叠,如果没有,则将其添加到结果列表中:

public static boolean dateRangeOverlap(Date givenStartDate, Date givenEndDate, Date listItemStartDate, Date listItemEndDate)
{
    boolean result = false;
    if (givenStartDate !=null && givenEndDate !=null && listItemStartDate !=null && listItemEndDate != null){
        result = (givenStartDate.getTime() <= listItemEndDate.getTime()) && (givenEndDate.getTime() >= listItemStartDate.getTime()); 
    }
    return result;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-11-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-07
    • 1970-01-01
    • 1970-01-01
    • 2020-07-06
    相关资源
    最近更新 更多