Déterminer Si Deux Plages De Dates Se Chevauchent
Étant donné deux plages de dates, Quel est le moyen le plus simple ou le plus efficace de déterminer si les deux plages de dates se chevauchent?
Par exemple, supposons que nous ayons des plages dénotées par des variables DateTime StartDate1
pour EndDate1
et StartDate2
à EndDate2
.
30 réponses
(StartA = StartB)
la Preuve:
Soit ConditionA signifie que DateRange a complètement après DateRange B_ |---- DateRange A ------|
|---Date Range B -----| _
(Vrai si StartA > EndB
)
Soit ConditionB signifie que DateRange A est complètement avant DateRange B|---- DateRange A -----| _
_ |---Date Range B ----|
(Vrai si EndA < StartB
)
Alors le chevauchement existe Si Ni A ni B n'est vrai -
(Si une plage n'est ni complètement après l'autre,
ni complètement avant l'autre,
puis ils doivent se chevaucher.)
Maintenant, L'une des lois de De Morgan dit que:
Not (A Or B)
Not A And Not B
Ce qui se traduit par: (StartA <= EndB) and (EndA >= StartB)
NOTE: Ceci inclut les conditions où les arêtes se chevauchent exactement. Si vous souhaitez exclure cela,
modifier les >=
opérateurs de >
, et <=
à <
NOTE2. Merci à @ Baodad, voir ce blog , le chevauchement réel est le moins de:
{ endA-startA
, endA - startB
, endB-startA
, endB - startB
}
(StartA <= EndB) and (EndA >= StartB)
(StartA <= EndB) and (StartB <= EndA)
NOTA3. Grâce à @tomosius, une version plus courte lit:DateRangesOverlap = max(start1, start2) < min(end1, end2)
C'est en fait un raccourci syntaxique pour ce qui est une implémentation plus longue, qui inclut des vérifications supplémentaires pour vérifier que les dates de début sont sur ou avant les dates de fin. En dérivant ceci d'en haut:
Si les dates de début et de fin peuvent être en panne, c'est-à-dire s'il est possible que startA > endA
ou startB > endB
, Vous devez également vérifier qu'elles sont en ordre, ce qui signifie que vous devez ajouter deux règles de validité supplémentaires: (StartA <= EndB) and (StartB <= EndA) and (StartA <= EndA) and (StartB <= EndB)
ou:(StartA <= EndB) and (StartA <= EndA) and (StartB <= EndA) and (StartB <= EndB)
ou,(StartA <= Min(EndA, EndB) and (StartB <= Min(EndA, EndB))
ou:(Max(StartA, StartB) <= Min(EndA, EndB)
Mais pour implémenter Min()
et Max()
, vous devez coder, (en utilisant C ternaire pour terseness),:(StartA > StartB? Start A: StartB) <= (EndA < EndB? EndA: EndB)
Je crois qu'il suffit de dire que les deux plages se chevauchent si:
(StartDate1 <= EndDate2) and (StartDate2 <= EndDate1)
Cet article bibliothèque de période de temps pour. NET décrit la relation de deux périodes de temps par l'Énumération PeriodRelation :
// ------------------------------------------------------------------------
public enum PeriodRelation
{
After,
StartTouching,
StartInside,
InsideStartTouching,
EnclosingStartTouching,
Enclosing,
EnclosingEndTouching,
ExactMatch,
Inside,
InsideEndTouching,
EndInside,
EndTouching,
Before,
} // enum PeriodRelation
Pour raisonner sur les relations temporelles (ou toute autre relation d'intervalle, en venir à cela), considérez L'algèbre D'intervalle D'Allen . Il décrit les 13 relations possibles que deux intervalles peuvent avoir l'un par rapport à l'autre. Vous pouvez trouver d'autres références - "Allen Interval" semble être un terme de recherche opérationnel. Vous pouvez également trouver des informations sur ces opérations dans de Snodgrass développant des Applications orientées temps dans SQL (PDF disponible en ligne à L'URL), et dans Date, Darwen et Lorentzos Temporelle de Données et le Modèle Relationnel (2002) ou du Temps et de la Théorie Relationnelle: Temporelle des Bases de données dans le Modèle Relationnel et SQL (2014; effectivement la deuxième édition de TD&RM).
La réponse courte (ish) est: étant donné deux intervalles de date A
et B
avec les composants .start
et .end
et la contrainte .start <= .end
, alors deux intervalles se chevauchent si:
A.end >= B.start AND A.start <= B.end
, Vous pouvez régler l'utilisation de >=
vs >
et <=
vs <
pour répondre à vos exigences relatives au degré de chevauchement.
ErikE commentaires:
Vous ne pouvez obtenir 13 Si vous comptez les choses drôles... Je peux obtenir "15 relations possibles que deux intervalles peuvent avoir" quand je deviens fou avec elle. Par comptage raisonnable, je n'en reçois que six, et si vous jetez le souci de savoir si A ou B vient en premier, je n'en reçois que trois (pas d'intersection, partiellement d'intersection, un entièrement dans l'autre). 15 va comme ceci: [avant:avant, commencer, à l'intérieur de la fin, après], [start:démarrer, dans la fin, après], [dans:dans la fin, après], [fin:fin, après], [après:après].
, je pense que vous ne pouvez pas compter deux entrées avant:avant " et "après:d'après". Je pourrais voir 7 entrées si vous assimilez certaines relations avec leurs inverses (voir le diagramme dans L'URL Wikipedia référencée; il a 7 entrées, dont 6 ont un inverse différent, avec des égaux n'ayant pas d'inverse distinct). Et si trois est sensible dépend de vos besoins.
----------------------|-------A-------|----------------------
|----B1----|
|----B2----|
|----B3----|
|----------B4----------|
|----------------B5----------------|
|----B6----|
----------------------|-------A-------|----------------------
|------B7-------|
|----------B8-----------|
|----B9----|
|----B10-----|
|--------B11--------|
|----B12----|
|----B13----|
----------------------|-------A-------|----------------------
Si le chevauchement lui-même doit également être calculé, vous pouvez utiliser la formule suivante:
overlap = max(0, min(EndDate1, EndDate2) - max(StartDate1, StartDate2))
if (overlap > 0) {
...
}
Toutes les solutions qui vérifient une multitude de conditions basées sur l'emplacement des plages les unes par rapport aux autres peuvent être grandement simplifiées en s'assurant simplement qu'une plage spécifique commence plus tôt! vous vous assurez que la première plage commence plus tôt (ou en même temps) en échangeant les plages si nécessaire à l'avant.
Ensuite, vous pouvez détecter le chevauchement si l'autre début de plage est inférieur ou égal à la première fin de plage (si les plages sont inclusives, contenant à la fois le début et la fin temps) ou inférieur à (si les plages incluent le début et excluent la fin).
En supposant inclusif aux deux extrémités, il n'y a que quatre possibilités dont une est un non-chevauchement:
|----------------------| range 1
|---> range 2 overlap
|---> range 2 overlap
|---> range 2 overlap
|---> range 2 no overlap
Le point final de la plage 2 n'y entre pas. Donc, en pseudo-code:
def doesOverlap (r1, r2):
if r1.s > r2.s:
swap r1, r2
if r2.s > r1.e:
return false
return true
Cela pourrait être simplifié encore plus en:
def doesOverlap (r1, r2):
if r1.s > r2.s:
swap r1, r2
return r2.s <= r1.e
Si les plages sont inclusives au début et exclusives à la fin, il vous suffit de remplacer >
par >=
dans la deuxième instruction if
(pour le premier segment de code: dans le deuxième segment de code, vous utiliseriez <
plutôt que <=
):
|----------------------| range 1
|---> range 2 overlap
|---> range 2 overlap
|---> range 2 no overlap
|---> range 2 no overlap
Vous limitez considérablement le nombre de vérifications que vous devez effectuer car vous supprimez la moitié de l'espace de problème tôt en vous assurant que la plage 1 ne commence jamais après la plage 2.
Voici encore une autre solution utilisant JavaScript. Spécialités de ma solution:
- gère les valeurs nulles comme infinity
- Suppose que la limite inférieure est inclusive et la limite supérieure exclusif.
- est Livré avec un tas de tests
Les tests sont basés sur des entiers mais puisque les objets date en JavaScript sont comparables, vous pouvez également ajouter deux objets date. Ou vous pourriez jeter dans la milliseconde timestamp.
Code:
/**
* Compares to comparable objects to find out whether they overlap.
* It is assumed that the interval is in the format [from,to) (read: from is inclusive, to is exclusive).
* A null value is interpreted as infinity
*/
function intervalsOverlap(from1, to1, from2, to2) {
return (to2 === null || from1 < to2) && (to1 === null || to1 > from2);
}
Essais:
describe('', function() {
function generateTest(firstRange, secondRange, expected) {
it(JSON.stringify(firstRange) + ' and ' + JSON.stringify(secondRange), function() {
expect(intervalsOverlap(firstRange[0], firstRange[1], secondRange[0], secondRange[1])).toBe(expected);
});
}
describe('no overlap (touching ends)', function() {
generateTest([10,20], [20,30], false);
generateTest([20,30], [10,20], false);
generateTest([10,20], [20,null], false);
generateTest([20,null], [10,20], false);
generateTest([null,20], [20,30], false);
generateTest([20,30], [null,20], false);
});
describe('do overlap (one end overlaps)', function() {
generateTest([10,20], [19,30], true);
generateTest([19,30], [10,20], true);
generateTest([10,20], [null,30], true);
generateTest([10,20], [19,null], true);
generateTest([null,30], [10,20], true);
generateTest([19,null], [10,20], true);
});
describe('do overlap (one range included in other range)', function() {
generateTest([10,40], [20,30], true);
generateTest([20,30], [10,40], true);
generateTest([10,40], [null,null], true);
generateTest([null,null], [10,40], true);
});
describe('do overlap (both ranges equal)', function() {
generateTest([10,20], [10,20], true);
generateTest([null,20], [null,20], true);
generateTest([10,null], [10,null], true);
generateTest([null,null], [null,null], true);
});
});
Résultat lorsqu'il est exécuté avec karma & jasmine & PhantomJS:
PhantomJS 1.9.8 (Linux): exécuté 20 de 20 succès (0.003 secondes / 0.004 secondes)
Je sais que cela a été étiqueté comme agnostique, mais pour vous tous implémentant en Java: ne réinventez pas la roue et utilisez Joda Time.
Je ferais
StartDate1.IsBetween(StartDate2, EndDate2) || EndDate1.IsBetween(StartDate2, EndDate2)
Où IsBetween
est quelque chose comme
public static bool IsBetween(this DateTime value, DateTime left, DateTime right) {
return (value > left && value < right) || (value < left && value > right);
}
La solution affichée ici ne fonctionne pas pour toutes les plages qui se chevauchent...
----------------------|-------A-------|---------------------- |----B1----| |----B2----| |----B3----| |----------B4----------| |----------------B5----------------| |----B6----| ----------------------|-------A-------|---------------------- |------B7-------| |----------B8-----------| |----B9----| |----B10-----| |--------B11--------| |----B12----| |----B13----| ----------------------|-------A-------|----------------------
Ma solution de travail était:
AND ( ('start_date' BETWEEN STARTDATE AND ENDDATE) -- caters for inner and end date outer OR ('end_date' BETWEEN STARTDATE AND ENDDATE) -- caters for inner and start date outer OR (STARTDATE BETWEEN 'start_date' AND 'end_date') -- only one needed for outer range where dates are inside. )
Voici ma solution dans Java , qui fonctionne aussi sur des intervalles illimités
private Boolean overlap (Timestamp startA, Timestamp endA,
Timestamp startB, Timestamp endB)
{
return (endB == null || startA == null || !startA.after(endB))
&& (endA == null || startB == null || !endA.before(startB));
}
C'était ma solution javascript Avec moment.js:
// Current row dates
var dateStart = moment("2014-08-01", "YYYY-MM-DD");
var dateEnd = moment("2014-08-30", "YYYY-MM-DD");
// Check with dates above
var rangeUsedStart = moment("2014-08-02", "YYYY-MM-DD");
var rangeUsedEnd = moment("2014-08-015", "YYYY-MM-DD");
// Range covers other ?
if((dateStart <= rangeUsedStart) && (rangeUsedEnd <= dateEnd)) {
return false;
}
// Range intersects with other start ?
if((dateStart <= rangeUsedStart) && (rangeUsedStart <= dateEnd)) {
return false;
}
// Range intersects with other end ?
if((dateStart <= rangeUsedEnd) && (rangeUsedEnd <= dateEnd)) {
return false;
}
// All good
return true;
Voici le code qui fait la magie:
var isOverlapping = ((A == null || D == null || A <= D)
&& (C == null || B == null || C <= B)
&& (A == null || B == null || A <= B)
&& (C == null || D == null || C <= D));
Où..
- A - > 1Start
- B - > 1End
- C - > 2Start
- D - > 2End
Preuve? Consultez ce test code de la console gist .
Dans le cas où vous utilisez une plage de dates qui n'est pas encore terminée (toujours en cours), par exemple non définie endDate = '0000-00-00' vous ne pouvez pas utiliser entre parce que 0000-00-00 n'est pas une date valide!
J'ai utilisé cette solution:
(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
Si startdate2 est supérieur alors enddate il n'y a pas de chevauchement!
Le plus simple
Le moyen le plus simple est d'utiliser une bibliothèque dédiée bien conçue pour le travail date-heure.
someInterval.overlaps( anotherInterval )
Java.temps & ThreeTen-Extra
Le meilleur dans l'entreprise est l'java.time
cadre intégré dans Java 8 et les versions ultérieures. Ajoutez à cela le projet ThreeTen-Extra qui complète java.temps avec des classes supplémentaires, en particulier le Interval
on a besoin de classe.
Quant à la balise language-agnostic
sur cette Question, le le code source des deux projets est disponible pour une utilisation dans d'autres langues (attention à leurs licences).
Interval
Le org.threeten.extra.Interval
la classe est pratique, mais nécessite des moments de date-heure (java.time.Instant
objets) plutôt que des valeurs de date uniquement. Nous procédons donc en utilisant le premier moment de la journée en UTC pour représenter la date.
Instant start = Instant.parse( "2016-01-01T00:00:00Z" );
Instant stop = Instant.parse( "2016-02-01T00:00:00Z" );
Créez un Interval
pour représenter cette période de temps.
Interval interval_A = Interval.of( start , stop );
On peut aussi définir un Interval
avec un moment de départ plus un Duration
.
Instant start_B = Instant.parse( "2016-01-03T00:00:00Z" );
Interval interval_B = Interval.of( start_B , Duration.of( 3 , ChronoUnit.DAYS ) );
Comparer au test pour les chevauchements est facile.
Boolean overlaps = interval_A.overlaps( interval_B );
, Vous pouvez comparer une Interval
contre un autre Interval
ou Instant
:
Tous ceux-ci utilisent l'approche Half-Open
pour définir une portée de le temps où le début est inclusive et la fin est exclusive.
Ceci est une extension de l'excellente réponse de @charles-bretana.
La réponse ne fait cependant pas de distinction entre les intervalles ouverts, fermés et semi-ouverts (ou semi-fermés).
Cas 1: A, B sont des intervalles fermés
A = [StartA, EndA]
B = [StartB, EndB]
[---- DateRange A ------] (True if StartA > EndB)
[--- Date Range B -----]
[---- DateRange A -----] (True if EndA < StartB)
[--- Date Range B ----]
Chevauchement iff: (StartA <= EndB) and (EndA >= StartB)
Cas 2: A, B sont des intervalles ouverts
A = (StartA, EndA)
B = (StartB, EndB)
(---- DateRange A ------) (True if StartA >= EndB)
(--- Date Range B -----)
(---- DateRange A -----) (True if EndA <= StartB)
(--- Date Range B ----)
Chevauchement iff: (StartA < EndB) and (EndA > StartB)
Cas 3: A, B droit ouvert
A = [StartA, EndA)
B = [StartB, EndB)
[---- DateRange A ------) (True if StartA >= EndB)
[--- Date Range B -----)
[---- DateRange A -----) (True if EndA <= StartB)
[--- Date Range B ----)
Condition de chevauchement: (StartA < EndB) and (EndA > StartB)
Cas 4 : A, B laissé ouvert
A = (StartA, EndA]
B = (StartB, EndB]
(---- DateRange A ------] (True if StartA >= EndB)
(--- Date Range B -----]
(---- DateRange A -----] (True if EndA <= StartB)
(--- Date Range B ----]
Condition de chevauchement: (StartA < EndB) and (EndA > StartB)
Cas 5 : a droit ouvert, B fermé
A = [StartA, EndA)
B = [StartB, EndB]
[---- DateRange A ------) (True if StartA > EndB)
[--- Date Range B -----]
[---- DateRange A -----) (True if EndA <= StartB)
[--- Date Range B ----]
Condition de chevauchement: (StartA <= EndB) and (EndA > StartB)
Etc...
Enfin, la condition générale pour que deux intervalles se chevauchent est
(StartA StartB)
Où transforme une inégalité stricte en une inégalité non stricte chaque fois que la comparaison est faite entre deux inclus terminaison.
Voici une méthode générique qui peut être utile localement.
// 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
*/
}
Dans Microsoft SQL SERVER - fonction SQL
CREATE FUNCTION IsOverlapDates
(
@startDate1 as datetime,
@endDate1 as datetime,
@startDate2 as datetime,
@endDate2 as datetime
)
RETURNS int
AS
BEGIN
DECLARE @Overlap as int
SET @Overlap = (SELECT CASE WHEN (
(@startDate1 BETWEEN @startDate2 AND @endDate2) -- caters for inner and end date outer
OR
(@endDate1 BETWEEN @startDate2 AND @endDate2) -- caters for inner and start date outer
OR
(@startDate2 BETWEEN @startDate1 AND @endDate1) -- only one needed for outer range where dates are inside.
) THEN 1 ELSE 0 END
)
RETURN @Overlap
END
GO
--Execution of the above code
DECLARE @startDate1 as datetime
DECLARE @endDate1 as datetime
DECLARE @startDate2 as datetime
DECLARE @endDate2 as datetime
DECLARE @Overlap as int
SET @startDate1 = '2014-06-01 01:00:00'
SET @endDate1 = '2014-06-01 02:00:00'
SET @startDate2 = '2014-06-01 01:00:00'
SET @endDate2 = '2014-06-01 01:30:00'
SET @Overlap = [dbo].[IsOverlapDates] (@startDate1, @endDate1, @startDate2, @endDate2)
SELECT Overlap = @Overlap
public static class NumberExtensionMethods
{
public static Boolean IsBetween(this Int64 value, Int64 Min, Int64 Max)
{
if (value >= Min && value <= Max) return true;
else return false;
}
public static Boolean IsBetween(this DateTime value, DateTime Min, DateTime Max)
{
Int64 numricValue = value.Ticks;
Int64 numericStartDate = Min.Ticks;
Int64 numericEndDate = Max.Ticks;
if (numricValue.IsBetween(numericStartDate, numericEndDate) )
{
return true;
}
return false;
}
}
public static Boolean IsOverlap(DateTime startDate1, DateTime endDate1, DateTime startDate2, DateTime endDate2)
{
Int64 numericStartDate1 = startDate1.Ticks;
Int64 numericEndDate1 = endDate1.Ticks;
Int64 numericStartDate2 = startDate2.Ticks;
Int64 numericEndDate2 = endDate2.Ticks;
if (numericStartDate2.IsBetween(numericStartDate1, numericEndDate1) ||
numericEndDate2.IsBetween(numericStartDate1, numericEndDate1) ||
numericStartDate1.IsBetween(numericStartDate2, numericEndDate2) ||
numericEndDate1.IsBetween(numericStartDate2, numericEndDate2))
{
return true;
}
return false;
}
if (IsOverlap(startdate1, enddate1, startdate2, enddate2))
{
Console.WriteLine("IsOverlap");
}
Utilisation de Java util.Date, voici ce que j'ai fait.
public static boolean checkTimeOverlaps(Date startDate1, Date endDate1, Date startDate2, Date endDate2)
{
if (startDate1 == null || endDate1 == null || startDate2 == null || endDate2 == null)
return false;
if ((startDate1.getTime() <= endDate2.getTime()) && (startDate2.getTime() <= endDate1.getTime()))
return true;
return false;
}
La façon la plus simple de le faire à mon avis serait de comparer Si EndDate1 est avant StartDate2 et EndDate2 est avant StartDate1.
Cela bien sûr si vous envisagez des intervalles où StartDate est toujours avant EndDate.
J'ai eu une situation où nous avions des dates au lieu de datetimes, et les dates ne pouvaient se chevaucher que sur le début / la fin. Exemple ci-dessous:
(Le vert est l'intervalle courant, les blocs bleus sont des intervalles valides, les rouges sont des intervalles qui se chevauchent).
J'ai adapté la réponse de Ian Nelson à la solution suivante:
(startB <= startA && endB > startA)
|| (startB >= startA && startB < endA)
Cela correspond à tous les cas de chevauchement mais ignore les cas de chevauchement autorisés.
La solution mathématique donnée par @ Bretana est bonne mais néglige deux détails spécifiques:
- aspect des intervalles fermés ou semi-ouverts
- intervalles vides
A propos de l'état fermé ou ouvert des limites d'intervalle, la solution de @ Bretana valide pour les intervalles fermés
(StartA = StartB)
Peut être réécrit pour les intervalles semi-ouverts à:
(StartA StartB)
Cette correction est nécessaire car une limite d'intervalle ouverte n'appartient pas à la plage de valeurs d'un intervalle par définition.
Et environ intervalles vides , Eh bien, ici la relation montrée ci-dessus ne tient pas. Les intervalles vides qui ne contiennent aucune valeur valide par définition doivent être traités comme cas particulier. Je le démontre par ma bibliothèque de temps Java Time4J via cet exemple:
MomentInterval a = MomentInterval.between(Instant.now(), Instant.now().plusSeconds(2));
MomentInterval b = a.collapse(); // make b an empty interval out of a
System.out.println(a); // [2017-04-10T05:28:11,909000000Z/2017-04-10T05:28:13,909000000Z)
System.out.println(b); // [2017-04-10T05:28:11,909000000Z/2017-04-10T05:28:11,909000000Z)
Le premier support carré "["indique un début fermé tandis que le dernier crochet") " indique une extrémité ouverte.
System.out.println(
"startA < endB: " + a.getStartAsInstant().isBefore(b.getEndAsInstant())); // false
System.out.println(
"endA > startB: " + a.getEndAsInstant().isAfter(b.getStartAsInstant())); // true
System.out.println("a overlaps b: " + a.intersects(b)); // a overlaps b: false
Comme indiqué ci-dessus, les intervalles vides violent la condition de chevauchement ci-dessus (en particulier startA
if (StartDate1 > StartDate2) swap(StartDate, EndDate);
(StartDate1 <= EndDate2) and (StartDate2 <= EndDate1);
Divisez le problème en cas, puis gérez chaque cas .
La situation "deux plages de dates se croisent" est couverte par deux cas - la première plage de dates commence dans la seconde, ou la deuxième plage de dates commence dans la première.
, Vous pouvez essayer ceci:
//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);
C'était ma solution, elle renvoie true lorsque les valeurs ne se chevauchent pas:
X DÉBUT 1 Y FIN 1
UN DÉBUT 2 B FIN 2
TEST1: (X <= A || X >= B)
&&
TEST2: (Y >= B || Y <= A)
&&
TEST3: (X >= B || Y <= A)
X-------------Y
A-----B
TEST1: TRUE
TEST2: TRUE
TEST3: FALSE
RESULT: FALSE
---------------------------------------
X---Y
A---B
TEST1: TRUE
TEST2: TRUE
TEST3: TRUE
RESULT: TRUE
---------------------------------------
X---Y
A---B
TEST1: TRUE
TEST2: TRUE
TEST3: TRUE
RESULT: TRUE
---------------------------------------
X----Y
A---------------B
TEST1: FALSE
TEST2: FALSE
TEST3: FALSE
RESULT: FALSE
Pour ruby, j'ai aussi trouvé ceci:
class Interval < ActiveRecord::Base
validates_presence_of :start_date, :end_date
# Check if a given interval overlaps this interval
def overlaps?(other)
(start_date - other.end_date) * (other.start_date - end_date) >= 0
end
# Return a scope for all interval overlapping the given interval, including the given interval itself
named_scope :overlapping, lambda { |interval| {
:conditions => ["id <> ? AND (DATEDIFF(start_date, ?) * DATEDIFF(?, end_date)) >= 0", interval.id, interval.end_date, interval.start_date]
}}
end
Trouvé ici avec une belle explication -> http://makandracards.com/makandra/984-test-if-two-date-ranges-overlap-in-ruby-or-rails
La requête ci-dessous me donne les ID pour lesquels la plage de dates fournie (dates de début et de fin chevauche l'une des dates (dates de début et de fin) dans mon table_name
select id from table_name where (START_DT_TM >= 'END_DATE_TIME' OR
(END_DT_TM BETWEEN 'START_DATE_TIME' AND 'END_DATE_TIME'))
La réponse est trop simple pour moi, j'ai donc créé une instruction SQL dynamique plus générique qui vérifie si une personne a des dates qui se chevauchent.
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)