在Java中找到多个日期间隔之间的差异

我想从给定的时间间隔集合B,C和D中减去主时间间隔A,以获得完全不重叠的日期时间间隔的输出。 B,C和D的间隔可以是几年或几个月。但是A只能是90天。

A = ["2015-01-01 00:00","2015-01-20 00:00"]
B = ["2015-01-05 00:00","2015-01-10 00:00"]
C = ["2015-01-11 00:00","2015-01-14 00:00"]
D = ["2015-01-19 00:00","2015-01-25 00:00"]

1                  A               20
|----------------------------------|
    |---------|   |----------|   |------------|
    5    B    9  11    C    14  19    D      25

理想的输出: {1,2,3,4,10,15,16,17,18}

1   4         10         15     18
|---|         |          |------|

到目前为止我做了什么?

I have iterated all the entries from A(1-20) in a list and all other entries B,C and D in another list and find out A-(B+C+D).
This is surely the longest way because the duration can be of several years.

请建议执行此操作的最快方法。

shenhaizhe 回答:在Java中找到多个日期间隔之间的差异

我假设所有给定的时间间隔都在同一月份,然后您可以使用以下代码段标记属于该时间间隔的每一天,并将结果存储到数组中。最后,您可以遍历此数组来了解非重叠间隔。

代码段

String pattern = "yyyy-MM-dd HH:mm";
String[] a = {"2015-01-01 00:00","2015-01-20 00:00"};
String[] b = {"2015-01-05 00:00","2015-01-10 00:00"};
String[] c = {"2015-01-11 00:00","2015-01-14 00:00"};
String[] d = {"2015-01-19 00:00","2015-01-25 00:00"};

String days[] = new String[31];
Arrays.fill(days,"X");

Arrays.fill(days,LocalDateTime.parse(a[0],DateTimeFormatter.ofPattern(pattern)).getDayOfMonth()-1,LocalDateTime.parse(a[1],DateTimeFormatter.ofPattern(pattern)).getDayOfMonth(),"A");

Arrays.fill(days,LocalDateTime.parse(b[0],LocalDateTime.parse(b[1],"B");

Arrays.fill(days,LocalDateTime.parse(c[0],LocalDateTime.parse(c[1],"C");

Arrays.fill(days,LocalDateTime.parse(d[0],LocalDateTime.parse(d[1],"D");
System.out.println(Arrays.toString(days));

控制台输出

  

[A,A,A,A,B,B,B,B,B,B,C,C,C,C,A,A,A,A,A,D,D,D,D,D, D,D,X,X,X,X,X,X]

,

ThreeTen-Extra

ThreeTen-Extra 库添加了Java 8和更高版本中内置的 java.time 框架的功能。

此库提供了两个类来表示时间轴上的时间跨度:

  • Interval代表一对瞬间,两个Instant物体。
  • LocalDateRange代表一对日期,两个LocalDate对象。

两个类都包含方便进行比较的方法,例如abutscontainsequalsintersectionoverlapsspan和{ {1}}。

定义范围

定义目标范围。

union

定义其他范围。

LocalDateRange target = LocalDateRange.of( 
    LocalDate.parse( "2015-01-01" ),LocalDate.parse( "2015-01-20" ),) ;

流日期

可能有一种更聪明的方法可以更有效率。但是通过这种方法,我们只需流式传输目标范围的所有日期。对于每个日期,我们询问是否有任何范围包含该日期。

流式处理范围的日期看起来像这样一行。

List < LocalDateRange > ranges = List.of(
        LocalDateRange.of( LocalDate.parse( "2015-01-05" ),LocalDate.parse( "2015-01-10" ) ),LocalDateRange.of( LocalDate.parse( "2015-01-11" ),LocalDate.parse( "2015-01-14" ) ),LocalDateRange.of( LocalDate.parse( "2015-01-19" ),LocalDate.parse( "2015-01-25" ) )
);

该行调用了我们编写的自定义方法。

List < LocalDate > dates = target.stream().filter( localDate -> this.rangesDoNotContain( ranges,localDate ) ).collect( Collectors.toList() );

结果:

  

dates.toString():[2015-01-01、2015-01-02、2015-01-03、2015-01-04、2015-01-10、2015-01-14、2015-01- 2015年1月15日,2015年1月17日,2015年1月18日]

流范围

我们可以进一步使用流来缩减此代码。通过用private boolean rangesDoNotContain ( List < LocalDateRange > ranges,LocalDate localDate ) { for ( LocalDateRange range : ranges ) { if ( range.contains( localDate ) ) { return false; } } return true; } 调用Stream::nonMatch,我们可以消除我们编写的ranges.stream()方法。

rangesDoNotContain

让我们包装该代码以使其更具可读性。然后,使参数的类型明确。

List < LocalDate > list = target.stream().filter( localDate -> ranges.stream().noneMatch( range -> range.contains( localDate ) ) ).collect( Collectors.toList() );

相同的结果。

  

[2015-01-01、2015-01-02、2015-01-03、2015-01-04、2015-01-10、2015-01-14、2015-01-15、2015-01- 2015年1月16日,2015年1月18日]

如果您对lambda和流还不满意,当然可以使用常规循环编写所有这些内容。

半开放

请注意,我的结果与您的结果不太匹配。我的代码使用常用的Half-Open方法来定义时间跨度。在这种方法中,开始为包含,而结束为排他。这允许时间跨度整齐地彼此邻接,而不会重叠且没有间隙。我建议您也采用这种方法。

如果您拒绝我的建议,请注意List < LocalDate > list = target .stream() .filter( ( LocalDate localDate ) -> ranges .stream() .noneMatch( ( LocalDateRange range ) -> range.contains( localDate ) ) ) .collect( Collectors.toList() ) ; 可以使用其他工厂方法来使用全封闭方法,其中开始和结束都包括在内。

,

我的图书馆Time4J根据您的期望A-(B + C + D)直接为subtraction of intervals提供支持。

ChronoFormatter<PlainTimestamp> parser = 
  ChronoFormatter.ofTimestampPattern("uuuu-MM-dd HH:mm",PatternType.CLDR,Locale.ROOT);

// my assumption for your input,please adjust the interval pattern if necessary
String intervalPattern = "{0} / {1}";
String sa = "2015-01-01 00:00 / 2015-01-20 00:00";
String sb = "2015-01-05 00:00 / 2015-01-10 00:00"; 
String sc = "2015-01-11 00:00 / 2015-01-14 00:00";
String sd = "2015-01-19 00:00 / 2015-01-25 00:00";

TimestampInterval a = TimestampInterval.parse(sa,parser,intervalPattern);
TimestampInterval b = TimestampInterval.parse(sb,intervalPattern);
TimestampInterval c = TimestampInterval.parse(sc,intervalPattern);
TimestampInterval d = TimestampInterval.parse(sd,intervalPattern);

IntervalCollection<PlainTimestamp> result = 
  IntervalCollection.onTimestampAxis().plus(a).minus(Arrays.asList(b,c,d));

所得的间隔集合包含期望的间隔和期望的间隔(只需对结果调用getIntervals(),并调用PlainTimestamp.toTemporalAccessor()转换为LocalDateTime)。默认情况下,此处的所有间隔都是半开的,这意味着开始是包容性的,而结束是排斥性的。因此,使用天数和封闭边界char [和开放边界char):

[1-5),[10-11),[14-19)

几乎与您的期望“ {1,2,3,4,10,15,16,17,18}”相符,但14而不是15(我认为这只是您输入的错字)。 / p>

本文链接:https://www.f2er.com/3110214.html

大家都在问