gpt4 book ai didi

java - 找出一系列日期是否涵盖一个时间间隔

转载 作者:塔克拉玛干 更新时间:2023-11-01 22:07:54 30 4
gpt4 key购买 nike

我有两个对象日历

Calendar startCalendar = new GregorianCalendar(2013,0,31);

Calendar endCalendar = new GregorianCalendar();

我想知道上面列出的两个日期之间的间隔是否被n个其他对象对日历覆盖而没有间隔之间的空洞

示例 1:

Calendar startCalendar1(2013,0,31);
Calendar endCalendar1(2014,0,31);
Calendar startCalendar2(2013,5,31);
Calendar endCalendar2();

很好

例子2:

Calendar startCalendar1(2013,0,31);
Calendar endCalendar1(2014,0,31);
Calendar startCalendar2(2014,2,31);
Calendar endCalendar2();

不好

我使用 Java 6谢谢

最佳答案

第一种方法:仅使用 Java 6

当我看到像 2015-01-31 这样的日期示例时,我强烈怀疑您说的是截止日期间隔,否则选择月末可能显得有点奇怪。这是一种广泛传播且合理的方法。不幸的是,选择像 java.util.Calendar 这样代表瞬间(也是日期-时区组合)的数据类型与闭区间不协调。这种类似即时的类型在半开间隔下效果更好。结果是:

如果您决定只使用 Java-6 类型,那么您可以按照@guillaume girod-vitouchkina 的建议,尝试将所有 Calendar 对象转换为表示自 Unix 纪元以来经过的毫秒数的长值(以我的投票为例,如何在没有任何外部库的情况下执行此操作)。 但是您必须提前为每个Calendar对象(如果表示结束边界)添加额外的一天,以达到关闭日期间隔的效果。

当然,您仍然需要自己做一些自己开发的区间算术,如该答案中粗略显示的那样。如果你仔细研究其他提案和你自己的需求,你会发现最终的解决方案甚至需要的不仅仅是一个新的区间类或区间的基本比较。您还需要一个更高的抽象层,即在几个间隔之间定义操作。自己做这一切可能会引起一些头痛。另一方面:如果您具有良好的编程技能,那么实现基于 Long 的区间算法可能会节省一些性能开销,这是典型的额外区间库。

第二种方法:使用专用的区间库

我只知道四个 promise 处理间隔的库。不能使用@Basil Bourque 提到的Threeten-Extra,因为它需要Java-8。它的间隔类的缺点是只能处理瞬间,不能处理日历日期。也几乎不支持处理间隔集合。 Joda-Time 也是如此(它至少在 Java-6 上工作并且还提供专用的日历日期类型,即 LocalDate 但没有日期间隔)。

一个有趣的选择是使用 Guava 及其类 RangeSet ,特别是如果您决定继续使用 Calendar-objects 和 Longs。这个类对处理间隔之间的操作有一些支持——对我来说比使用简单的 Joda-Time 间隔类更有吸引力。

最后,您还可以选择使用我的库 Time4J,它有 range-package .我现在将针对您的问题展示一个完整的解决方案:

// our test interval
PlainDate start = PlainDate.of(2013, Month.JANUARY, 31);
PlainDate end = SystemClock.inLocalView().today();
DateInterval test = DateInterval.between(start, end);
IntervalCollection<PlainDate> icTest = IntervalCollection.onDateAxis().plus(test);

// two intervals for your GOOD case
PlainDate s1 = PlainDate.of(2013, Month.JANUARY, 31);
PlainDate e1 = PlainDate.of(2014, Month.JANUARY, 31);
DateInterval i1 = DateInterval.between(s1, e1);

PlainDate s2 = PlainDate.of(2013, Month.MAY, 31);
PlainDate e2 = end; // today
DateInterval i2 = DateInterval.between(s2, e2);

IntervalCollection<PlainDate> goodCase =
IntervalCollection.onDateAxis().plus(i1).plus(i2);

boolean covered = icTest.minus(goodCase).isEmpty();
System.out.println("Good case: " + covered); // true

// two intervals for your BAD case
PlainDate s3 = PlainDate.of(2013, Month.JANUARY, 31);
PlainDate e3 = PlainDate.of(2014, Month.JANUARY, 31);
DateInterval i3 = DateInterval.between(s3, e3);

PlainDate s4 = PlainDate.of(2014, Month.MARCH, 31);
PlainDate e4 = end; // today
DateInterval i4 = DateInterval.between(s4, e4);

IntervalCollection<PlainDate> badCase =
IntervalCollection.onDateAxis().plus(i3).plus(i4);

covered = icTest.minus(badCase).isEmpty();
System.out.println("Bad case: " + covered); // false

代码的最大部分只是区间构造。真正的区间运算本身是由这个小得惊人的代码片段完成的:

boolean covered = 
IntervalCollection.onDateAxis().plus(test).minus(
IntervalCollection.onDateAxis().plus(i1).plus(i2)
).isEmpty();

说明:如果test减去i1和i2的余数为空,则测试区间被区间i1和i2覆盖。

顺便说一句:默认情况下,Time4J 中的日期区间是闭区间。但是,如果您确实需要,可以将这些间隔更改为半开间隔(只需在给定的日期间隔内调用 withOpenEnd())。

如果您打算稍后迁移到 Java-8,您只需将 Time4J 版本更新到版本 4.x(v3.x 版本适用于 Java-6)并非常容易地转换为 Java-8 类型像 java.time.LocalDate(例如:PlainDate.from(localDate)LocalDate ld = plainDate.toTemporalAccessor())这样你就可以即使在未来,也可以继续使用 Time4J 来获得标准 Java 未涵盖的额外功能。

关于java - 找出一系列日期是否涵盖一个时间间隔,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34312128/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com