【问题标题】:How to check a timeperiod is overlapping another time period in java如何检查一个时间段是否与java中的另一个时间段重叠
【发布时间】:2013-06-10 23:53:45
【问题描述】:

如何检查一个时间段是否与同一天的另一个时间段重叠。

例如,

  1. 7:00AM 到 10:30AM 与 10:00AM 到 11:30AM 重叠
  2. 7:00AM 到 10:30AM 与 8:00AM 到 9:00AM 重叠
  3. 7:00AM 到 10:30AM 与 5:00AM 到 8:00AM 重叠

【问题讨论】:

  • 我们需要更多详细信息 - 这在某种程度上取决于您存储时间段的方式。是java.time.Period吗?一般来说,检查两个时间段是否重叠很简单 - 比较每个时间段的开始时间和结束时间。
  • 我没有存储我的时间段。我想找到重叠时间。例如(上午 7:00 到上午 10:30 与上午 10:00 到上午 11:30 重叠)这次是重叠的。像这样我有五十对时间。所以我想用另一对来验证每一对。
  • 当我说“你如何存储它”时,我的意思是数据类型是什么?它会影响可能的答案(正如有远见的人在他的回答中提到的那样,如果您使用的是 Joda time,则已经提供了此功能)。就我们所知,句点可能是文本字符串“7:00am to 10:30am”,需要解析。或者可以将时间存储为 Java 日期。或 0.0 的浮点值等于 1970-01-01 00:00 纪元。

标签: java time


【解决方案1】:

有一个简单的解决方案,这里表示为实用方法:

public static boolean isOverlapping(Date start1, Date end1, Date start2, Date end2) {
    return start1.before(end2) && start2.before(end1);
}

此代码要求两个周期之间至少有 1 毫秒的时间共享以返回 true

如果认为相邻时间段“重叠”(例如 10:00-10:30 和 10:30-11:00),则需要稍微调整逻辑:

public static boolean isOverlapping(Date start1, Date end1, Date start2, Date end2) {
    return !start1.after(end2) && !start2.after(end1);
}

这种逻辑更常出现在数据库查询中,但同样的方法适用于任何情况。

一旦你意识到它是多么简单,你首先会踢自己,然后把它存入银行!

【讨论】:

  • before (和after)严格来说是指之前。因此,句点长度不为零:start1.before(start1) == false.
  • @JoopEggen 我想知道有人对此发表评论需要多长时间。尽管这些示例都没有涵盖这种边缘情况,但我已经编辑了我的答案以提出一个替代方案,但同样优雅(比你的更好:)),如果它们被认为是重叠的,则可以满足邻接时期的解决方案。
  • 啊哈,布尔专家;然后为我的== false 道歉;)。仍然是第一个解决方案似乎最合适。
【解决方案2】:

tl;博士

( startA.isBefore( stopB ) ) && ( stopA.isAfter( startB ) ) 

LocalTime

如果您真的想在没有日期和时区上下文的情况下使用通用时间,请使用 LocalTime 类。

LocalTime startA = LocalTime.of( 7 , 0 );
LocalTime stopA = LocalTime.of( 10 , 30 );

LocalTime startB = LocalTime.of( 10 , 0 );
LocalTime stop2B = LocalTime.of( 11 , 30 );

验证数据,确保结尾在开头之后(或相等)。更简单的说法是“开始不是在结束之后”。

Boolean validA = ( ! startA.isAfter( stopA ) ) ;
Boolean validB = ( ! startB.isAfter( stop2B ) ) ;

根据Meno Hochschildthis Answer,使用半开放方法来定义开始包含而结束独占的时间跨度,我们可以使用这个逻辑:

(StartA StartB)

Boolean overlaps = ( 
    ( startA.isBefore( stopB ) ) 
    && 
    ( stopA.isAfter( startB ) ) 
) ;

请注意,LocalTime 仅限于一个通用的 24 小时一天。时间不能过去午夜,不能缠绕成另一个。 没有天可以考虑。验证您的输入以验证开始时间在结束之前,或者它们是相等的(如果这符合您的业务规则)。

if( stopA.isBefore( startA ) ) { … handle error  } 

if( stopB.isBefore( startB ) ) { … handle error  } 

ZonedDateTime

如果您想测试时间线上的实际时刻,您必须将这些时间对象调整到日期和时区的上下文中。应用ZoneId 以获取ZonedDateTime 对象。

ZoneId z = ZoneId.of( "America/Montreal" );
LocalDate today = LocalDate.now( z );
ZonedDateTime zdt = ZonedDateTime.of( today , startA , z);


关于java.time

java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.DateCalendarSimpleDateFormat

Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。

要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310

从哪里获得 java.time 类?

ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore

【讨论】:

    【解决方案3】:

    如果间隔打开(例如,某些进程尚未完成)并且结束日期可能为空:

    public static boolean isOverlapping(Date start1, Date end1, Date start2, Date end2)
    {
        return
                ((null == end2) || start1.before(end2)) &&
                ((null == end1) || start2.before(end1)) ;
    }
    

    【讨论】:

      【解决方案4】:

      JOda Time 有这个functionality baked in。它构建得非常好,并且在 JSR 路线上取代了损坏的 Java 日历 API。您可能应该考虑使用它。

      【讨论】:

        【解决方案5】:

        编辑:

        工作方法如下:

        public boolean isOverlapping(Date start1, Date end1, Date start2, Date end2) {
            return start1.compareTo(end2) <= 0 && end1.compareTo(start2) >= 0;
        }
        

        这里是每个人都可以尝试的证据:

        @Test
        public void isOverlapping_base() {
            Assert.assertTrue(isOverlapping(getDate(2014, 1, 1),
                    getDate(2014, 3, 31), getDate(2014, 1, 2),
                    getDate(2014, 4, 1)));
            
            Assert.assertTrue(isOverlapping(getDate(2014, 1, 2),
                    getDate(2014, 4, 1), getDate(2014, 1, 1),
                    getDate(2014, 3, 31)));
            
            Assert.assertTrue(isOverlapping(getDate(2014, 1, 1),
                    getDate(2014, 4, 1), getDate(2014, 1, 2),
                    getDate(2014, 3, 31)));
            
            Assert.assertTrue(isOverlapping(getDate(2014, 1, 2),
                    getDate(2014, 3, 31), getDate(2014, 1, 1),
                    getDate(2014, 4, 1)));
            
            Assert.assertFalse(isOverlapping(getDate(2014, 1, 1),
                    getDate(2014, 1, 31), getDate(2014, 3, 1),
                    getDate(2014, 3, 31)));
            
            Assert.assertFalse(isOverlapping(getDate(2014, 3, 1),
                    getDate(2014, 3, 31), getDate(2014, 1, 1),
                    getDate(2014, 1, 31)));
        }
        
        Date getDate(int year, int month, int date) {
            Calendar working = Calendar.getInstance();
            working.set(year, month - 1, date, 0, 0, 0); 
            working.set(Calendar.MILLISECOND, 0);
            return working.getTime();
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-06-22
          • 2020-03-22
          • 2019-11-06
          • 2021-09-08
          • 2013-07-27
          相关资源
          最近更新 更多