Determinar si dos rangos de fechas se superponen
Dados dos intervalos de fechas, ¿cuál es la forma más sencilla o eficaz de determinar si los dos intervalos de fechas se superponen?
Como ejemplo, supongamos que tenemos rangos indicados por variables DateTime StartDate1
hasta EndDate1
y StartDate2
hasta EndDate2
.
(InicioA <= FinB) y (FinA >= InicioB)
Prueba:
Deje que ConditionA signifique que DateRange A está completamente después de DateRange B
_ |---- DateRange A ------|
|---Date Range B -----| _
(Verdadero si StartA > EndB
)
Deje que ConditionB signifique que DateRange A es completamente anterior a DateRange B
|---- DateRange A -----| _
_ |---Date Range B ----|
(Verdadero si EndA < StartB
)
Entonces, la superposición existe si ni A ni B son verdaderos
(si un rango no está completamente después del otro
ni completamente antes del otro, entonces deben superponerse).
Ahora bien, una de las leyes de De Morgan dice que:
Not (A Or B)
<=> Not A And Not B
Lo que se traduce en:(StartA <= EndB) and (EndA >= StartB)
NOTA: Esto incluye condiciones en las que los bordes se superponen exactamente. Si desea excluir eso,
cambie los >=
operadores a >
y <=
a<
NOTA 2. Gracias a @Baodad, mira este blog , la superposición real es menor de:
{ endA-startA
,,, }endA - startB
endB-startA
endB - startB
(StartA <= EndB) and (EndA >= StartB)
(StartA <= EndB) and (StartB <= EndA)
NOTA 3. Gracias a @tomosius, una versión más corta dice:
DateRangesOverlap = max(start1, start2) < min(end1, end2)
Este es en realidad un atajo sintáctico para lo que es una implementación más larga, que incluye comprobaciones adicionales para verificar que las fechas de inicio sean iguales o anteriores a las fechas de finalización. Derivando esto desde arriba:
Si las fechas de inicio y finalización pueden estar desordenadas, es decir, si es posible que startA > endA
o startB > endB
, entonces también debes verificar que estén en orden, lo que significa que debes agregar dos reglas de validez adicionales:
(StartA <= EndB) and (StartB <= EndA) and (StartA <= EndA) and (StartB <= EndB)
o:
(StartA <= EndB) and (StartA <= EndA) and (StartB <= EndA) and (StartB <= EndB)
o,
(StartA <= Min(EndA, EndB) and (StartB <= Min(EndA, EndB))
o:
(Max(StartA, StartB) <= Min(EndA, EndB)
Pero para implementar Min()
and Max()
, debe codificar (usando C ternario para mayor concisión):
((StartA > StartB) ? StartA : StartB) <= ((EndA < EndB) ? EndA : EndB)
Creo que basta con decir que los dos rangos se superponen si:
(StartDate1 <= EndDate2) and (StartDate2 <= EndDate1)
Este artículo Biblioteca de períodos de tiempo para .NET describe la relación de dos períodos de tiempo mediante la enumeración PeriodRelation :
// ------------------------------------------------------------------------
public enum PeriodRelation
{
After,
StartTouching,
StartInside,
InsideStartTouching,
EnclosingStartTouching,
Enclosing,
EnclosingEndTouching,
ExactMatch,
Inside,
InsideEndTouching,
EndInside,
EndTouching,
Before,
} // enum PeriodRelation