找出一系列间隔是否包含日期 [英] Find out if a series of dates covering an interval

查看:90
本文介绍了找出一系列间隔是否包含日期的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个对象日历

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

Calendar endCalendar = new GregorianCalendar();

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

I want to know if the interval between the two dates listed above is covered by n of other objects pair calendars without holes between intervals

示例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
谢谢

I use Java 6 Thanks

推荐答案

第一种方法:仅使用Java 6

当我看到您的日期示例,例如 2015-01-31 时,我很怀疑您在谈论关闭日期间隔,否则选择月底可能会有些奇怪。这是一种广泛且合理的方法。不幸的是,选择诸如 java.util.Calendar 之类的数据类型表示一个瞬间(也包括一个date-time-zone-combo),这与封闭的间隔并不协调。这种类似瞬时的类型在半开间隔内效果更好。结果是:

When I see your date examples like 2015-01-31 then I get the strong suspicion that you speak about closed date intervals otherwise choosing the end of a month might appear a little bit strange. This is a wide spread and reasonable approach. Unfortunately choosing a data type like java.util.Calendar representing an instant (also a date-time-zone-combo, too) is not in harmony with closed intervals. Such instant-like types work better with half-open intervals. The consequence is:

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

If you decide to use only Java-6-types then you can try to convert all Calendar-objects to Long-values representing the elapsed millisecs since Unix epoch as suggested by @guillaume girod-vitouchkina (has got my upvote as an example how to do this without any external library) . But you have to add an extra day to every single Calendar-object (if representing an end boundary) in advance to achieve the effect of closed date intervals.

当然,您仍然必须自己粗略地进行一些区间增长算术运算,如该答案所示。如果仔细研究其他建议和您自己的要求,您会发现最终解决方案甚至不仅仅需要一个新的间隔类或间隔的基本比较。您还将需要更高的抽象层,即几个间隔之间的已定义操作。自己这样做可能会引起一些头痛。另一方面:如果您具有良好的编程技能,则实施基于长整数的区间算法可能会节省一些额外的区间库通常需要的性能开销。

And of course, you have still to do some home grown interval arithmetic yourself as shown in that answer in a sketchy way. If you carefully study the other proposals and your own requirements you will find that the final solution even requires more than just a new interval class or basic comparisons of intervals. You will also need a higher abstraction layer, namely defined operations between several intervals. Doing this all yourself might cause some headache. On the other hand: Implementing a Long-based interval arithmetic might save some performance overhead as typical for an extra interval library if you have good programming skills.

第二方法:使用专用的时间间隔库

我只知道四个承诺处理时间间隔的库。 @Basil Bourque提到的 Threeten-Extra 无法使用,因为它需要Java-8。它的间隔类的缺点是只能处理即时信息,而不能处理日历日期。几乎不支持处理时间间隔集合。对于 Joda-Time (至少可以在Java-6上运行,并且还提供了专用的日历日期类型,即 LocalDate ),也可以这样说。

I only know four libraries which promise to handle intervals. Threeten-Extra as mentioned by @Basil Bourque cannot be used because it requires Java-8. Its interval class has the disadvantage to handle instants only, but not calendar dates. There is also almost no support for handling collections of intervals. The same can be said for Joda-Time (which is at least working on Java-6 and also offers a dedicated calendar date type, namely LocalDate but no date intervals).

一个有趣的选择是使用 Guava 及其类 RangeSet ,尤其是如果您决定继续使用 Calendar -对象和Longs。此类为处理间隔之间的操作提供了一些支持-对我来说,比使用简单的Joda-Time间隔类更具吸引力。

An interesting option is using Guava and its class RangeSet, especially if you decide to continue using Calendar-objects and Longs. This class has some support for handling operations between intervals - for me much more appealing than using the simple interval class of Joda-Time.

最后,您还可以选择使用我的图书馆 Time4J ,其中具有 range-包。现在,我将为您的问题展示一个完整的解决方案:

Finally you also have the option to use my library Time4J which has the range-package. I will show now a complete solution for your problem:

// 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

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

The biggest part of code is just interval construction. The real interval arithmetic itself is done by this surprisingly small code fragment:

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

说明:如果其余部分相减,则测试间隔由间隔i1和i2覆盖

顺便说一句:默认情况下,Time4J中的日期间隔为关闭间隔。您可以根据需要将这些间隔更改为半开间隔(只需在给定的日期间隔上调用 withOpenEnd())。

By the way: Date intervals in Time4J are closed intervals by default. You can change these intervals to half open intervals however if you really want (simply by calling withOpenEnd() on a given date interval).

如果您打算以后再迁移到Java-8,则只需将Time4J版本更新为版本4.x(版本v3.x适用于Java-6)即可轻松转换为Java -8个类型,例如 java.time.LocalDate (例如: PlainDate.from(localDate) LocalDate ld = plainDate.toTemporalAccessor()),因此您甚至可以在将来继续使用Time4J来实现标准Java所未涵盖的其他功能。

And if you plan to migrate to Java-8 later, you can just update the Time4J-version to version line 4.x (version v3.x is for Java-6) and get very easy conversions to Java-8 types like java.time.LocalDate (for example: PlainDate.from(localDate) or LocalDate ld = plainDate.toTemporalAccessor()) so you can continue to use Time4J for extra features not covered by standard Java even in the future.

这篇关于找出一系列间隔是否包含日期的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆