如何检查同一天内的时间段是否重叠。
例如:
- 上午7:00到10:30与上午10:00到11:30重叠
- 上午7:00到10:30与上午8:00到9:00重叠
- 上午7:00到10:30与上午5:00到8:00重叠
这里有一个简单的解决方案,表达为一个实用方法:
public static boolean isOverlapping(Date start1, Date end1, Date start2, Date end2) {
return start1.before(end2) && start2.before(end1);
}
这段代码需要在两个时间段之间至少有一毫秒的共享才会返回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
。 - Joop Eggen== false
表示歉意 ;). 不过第一个解决方案似乎最合适。 - Joop Eggen( 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 ) ) ;
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 8及更高版本。这些类取代了老旧的传统日期时间类,如java.util.Date
、Calendar
和SimpleDateFormat
。
Joda-Time项目现已进入维护模式,建议迁移至java.time类。
要了解更多,请参见Oracle教程。并在Stack Overflow上搜索许多示例和解释。规范是JSR 310。ThreeTen-Extra项目扩展了java.time的附加类。该项目是java.time可能未来添加的试验场。您可能会在这里找到一些有用的类,例如Interval
, YearWeek
, YearQuarter
以及更多。
public static boolean isOverlapping(Date start1, Date end1, Date start2, Date end2)
{
return
((null == end2) || start1.before(end2)) &&
((null == end1) || start2.before(end1)) ;
}
编辑:
以下是可行的方法:
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();
}
java.time.Period
吗?通常,检查两个时间段是否重叠很简单 - 比较每个时间段的开始和结束时间。 - icabod