给定两个日期范围,确定两个日期是否重叠的最简单或最有效的方法是什么?
例如,假设我们有由DateTime变量StartDate1到EndDate1和StartDate2到EndDate2表示的范围。
给定两个日期范围,确定两个日期是否重叠的最简单或最有效的方法是什么?
例如,假设我们有由DateTime变量StartDate1到EndDate1和StartDate2到EndDate2表示的范围。
当前回答
你可以试试这个:
//custom date for example
$d1 = new DateTime("2012-07-08");
$d2 = new DateTime("2012-07-11");
$d3 = new DateTime("2012-07-08");
$d4 = new DateTime("2012-07-15");
//create a date period object
$interval = new DateInterval('P1D');
$daterange = iterator_to_array(new DatePeriod($d1, $interval, $d2));
$daterange1 = iterator_to_array(new DatePeriod($d3, $interval, $d4));
array_map(function($v) use ($daterange1) { if(in_array($v, $daterange1)) print "Bingo!";}, $daterange);
其他回答
这里有一个可以在本地使用的通用方法。
// Takes a list and returns all records that have overlapping time ranges.
public static IEnumerable<T> GetOverlappedTimes<T>(IEnumerable<T> list, Func<T, bool> filter, Func<T,DateTime> start, Func<T, DateTime> end)
{
// Selects all records that match filter() on left side and returns all records on right side that overlap.
var overlap = from t1 in list
where filter(t1)
from t2 in list
where !object.Equals(t1, t2) // Don't match the same record on right side.
let in1 = start(t1)
let out1 = end(t1)
let in2 = start(t2)
let out2 = end(t2)
where in1 <= out2 && out1 >= in2
let totover = GetMins(in1, out1, in2, out2)
select t2;
return overlap;
}
public static void TestOverlap()
{
var tl1 = new TempTimeEntry() { ID = 1, Name = "Bill", In = "1/1/08 1:00pm".ToDate(), Out = "1/1/08 4:00pm".ToDate() };
var tl2 = new TempTimeEntry() { ID = 2, Name = "John", In = "1/1/08 5:00pm".ToDate(), Out = "1/1/08 6:00pm".ToDate() };
var tl3 = new TempTimeEntry() { ID = 3, Name = "Lisa", In = "1/1/08 7:00pm".ToDate(), Out = "1/1/08 9:00pm".ToDate() };
var tl4 = new TempTimeEntry() { ID = 4, Name = "Joe", In = "1/1/08 3:00pm".ToDate(), Out = "1/1/08 8:00pm".ToDate() };
var tl5 = new TempTimeEntry() { ID = 1, Name = "Bill", In = "1/1/08 8:01pm".ToDate(), Out = "1/1/08 8:00pm".ToDate() };
var list = new List<TempTimeEntry>() { tl1, tl2, tl3, tl4, tl5 };
var overlap = GetOverlappedTimes(list, (TempTimeEntry t1)=>t1.ID==1, (TempTimeEntry tIn) => tIn.In, (TempTimeEntry tOut) => tOut.Out);
Console.WriteLine("\nRecords overlap:");
foreach (var tl in overlap)
Console.WriteLine("Name:{0} T1In:{1} T1Out:{2}", tl.Name, tl.In, tl.Out);
Console.WriteLine("Done");
/* Output:
Records overlap:
Name:Joe T1In:1/1/2008 3:00:00 PM T1Out:1/1/2008 8:00:00 PM
Name:Lisa T1In:1/1/2008 7:00:00 PM T1Out:1/1/2008 9:00:00 PM
Done
*/
}
如果您使用的日期范围尚未结束(仍在进行中),例如未设置endDate='0000-00-00'您不能使用BETWEEN,因为0000-00-00不是有效日期!
我使用了这个解决方案:
(Startdate BETWEEN '".$startdate2."' AND '".$enddate2."') //overlap: starts between start2/end2
OR (Startdate < '".$startdate2."'
AND (enddate = '0000-00-00' OR enddate >= '".$startdate2."')
) //overlap: starts before start2 and enddate not set 0000-00-00 (still on going) or if enddate is set but higher then startdate2
如果startdate2高于enddate,则没有重叠!
答案对我来说太简单了,所以我创建了一个更通用的动态SQL语句,用于检查某人是否有重叠的日期。
SELECT DISTINCT T1.EmpID
FROM Table1 T1
INNER JOIN Table2 T2 ON T1.EmpID = T2.EmpID
AND T1.JobID <> T2.JobID
AND (
(T1.DateFrom >= T2.DateFrom AND T1.dateFrom <= T2.DateTo)
OR (T1.DateTo >= T2.DateFrom AND T1.DateTo <= T2.DateTo)
OR (T1.DateFrom < T2.DateFrom AND T1.DateTo IS NULL)
)
AND NOT (T1.DateFrom = T2.DateFrom)
这里是我的简化。假设时间间隔
| |
| |
不要重叠,xa<xb和ya<yb可以简化处理。上述条件可以简单检查。然后你会得到
ya yb
|--------|
xa |--|xb
|----|
|----|
ya > xa => return ya - xa < xb - xa
else => return xa < yb
正如您可能注意到的,第二个间隔仅在xa>=ya的情况下相关。
关于时间关系(或任何其他区间关系)的推理,请考虑Allen的区间代数。它描述了两个区间之间可能存在的13种关系。你可以找到其他参考资料——“艾伦间隔”似乎是一个有效的搜索词。您还可以在Snodgrass的《用SQL开发面向时间的应用程序》(PDF,网址为)、《日期、达文和洛伦兹时间数据与关系模型》(2002年)或《时间与关系理论:关系模型与SQL中的时间数据库》(2014年;实际上是TD&RM的第二版)中找到有关这些操作的信息。
简短的答案是:给定两个日期间隔A和B,其中包含.start和.end以及约束.start<=.end,则两个间隔重叠,如果:
A.end >= B.start AND A.start <= B.end
您可以调整>=vs>和<=vs<的使用,以满足重叠程度的要求。
ErikE评论:
如果你数点有趣的事情,你只能得到13。。。当我疯狂地计算时,我可以得到“两个区间可以有15种可能的关系”。通过合理的计算,我只能得到6种关系,如果你不在乎A还是B先出现,我只能获得3种关系(不相交,部分相交,一种完全在另一种内)。15是这样的:[之前:之前,开始,内部,结束,之后],[开始:开始,内部、结束,之后】,[内部:内部,结束、之后],[结束:结束,之后,],[之后:之后]。
我认为你不能计算“之前:之前”和“之后:之后”这两个条目。如果你将某些关系与它们的逆关系等同起来,我可以看到7个条目(参见参考维基百科URL中的图表;它有7个条目,其中6个条目具有不同的逆关系,而equals没有不同的逆)。三个是否合理取决于你的要求。
----------------------|-------A-------|----------------------
|----B1----|
|----B2----|
|----B3----|
|----------B4----------|
|----------------B5----------------|
|----B6----|
----------------------|-------A-------|----------------------
|------B7-------|
|----------B8-----------|
|----B9----|
|----B10-----|
|--------B11--------|
|----B12----|
|----B13----|
----------------------|-------A-------|----------------------