web-dev-qa-db-fra.com

Déterminer si deux plages de dates se chevauchent

Pour deux plages de dates, quel est le moyen le plus simple ou le plus efficace de déterminer si les deux plages se chevauchent?

Par exemple, supposons que nous ayons des plages désignées par les variables DateTime StartDate1 à EndDate1etStartDate2 à EndDate2.

1138
Ian Nelson

(StartA <= EndB) et (EndA> = StartB)

Preuve:
Laisser ConditionA dire que DateRange A complètement après DateRange B
_ |---- DateRange A ------| |---Date Range B -----| _
(Vrai si StartA > EndB)

Laissons à ConditionB le fait 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, alors 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)


REMARQUE: cela inclut les conditions dans lesquelles les bords se chevauchent exactement. Si vous souhaitez exclure cela,
change les opérateurs >= en >, et <= en <


NOTE 2. Grâce à @Baodad, voir ce blog , le chevauchement réel est le moindre de:
{endA-startA, endA - startB, endB-startA, endB - startB}

(StartA <= EndB) and (EndA >= StartB)(StartA <= EndB) and (StartB <= EndA)


NOTE 3. Grâce à @tomosius, une version plus courte se lit comme suit:
DateRangesOverlap = max(start1, start2) < min(end1, end2)
Il s'agit en fait d'un raccourci syntaxique pour une implémentation plus longue, qui inclut des vérifications supplémentaires pour vérifier que les dates de début sont égales ou antérieures aux dates de fin. En dérivant cela d'en haut:

Si les dates de début et de fin peuvent ne pas fonctionner correctement, 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 en 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 ternary pour la terseness):
(StartA > StartB? Start A: StartB) <= (EndA < EndB? EndA: EndB)

2120
Charles Bretana

Je pense qu'il suffit de dire que les deux plages se chevauchent si:

(StartDate1 <= EndDate2) and (StartDate2 <= EndDate1)
370
Ian Nelson

Cet article Bibliothèque de périodes pour .NET décrit la relation de deux périodes par l'énumération PeriodRelation :

// ------------------------------------------------------------------------
public enum PeriodRelation
{
    After,
    StartTouching,
    StartInside,
    InsideStartTouching,
    EnclosingStartTouching,
    Enclosing,
    EnclosingEndTouching,
    ExactMatch,
    Inside,
    InsideEndTouching,
    EndInside,
    EndTouching,
    Before,
} // enum PeriodRelation

enter image description here

104
user687474

Pour raisonner à propos des relations temporelles (ou de toute autre relation d'intervalle, y arriver), considérons 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 Snodgrass Développement d'applications temporelles en SQL (PDF disponible en ligne à l'adresse URL), et dans Date, Darwen et Lorentzos. Données temporelles et modèle relationnel (2002) ou Théorie temporelle et relationnelle: Bases de données temporelles 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 des composants .start et .end et la contrainte .start <= .end, deux intervalles se chevauchent si :

A.end >= B.start AND A.start <= B.end

Vous pouvez ajuster l'utilisation de >= vs > et <= vs < afin de répondre à vos exigences en matière de degré de chevauchement.


ErikE commente:

Vous ne pouvez obtenir que 13 si vous comptez les choses drôles… Je peux avoir "15 relations possibles que deux intervalles peuvent avoir" quand je deviens fou. En comptant judicieusement, je n’en ai que six, et si vous vous moquez de savoir si A ou B vient en premier, j’en ai seulement trois (pas d’intersection, pas de recoupement partiel, un dans l’autre). 15 va comme ceci: [avant: avant, début, intérieur, fin, après], [début: début, intérieur, fin, après], [dans: intérieur, fin, après], [fin: fin, après], [ après: après].

Je pense que vous ne pouvez pas compter les deux entrées 'avant: avant' et 'après: après'. Je pourrais voir 7 entrées si vous assimilez certaines relations à leurs inverses (voir le diagramme dans l'URL référencée de Wikipédia; il comporte 7 entrées, dont 6 ont un inverse différent, avec des égaux n'ayant pas d'inverse distinct). Et si trois est raisonnable dépend de vos besoins.

----------------------|-------A-------|----------------------
    |----B1----|
           |----B2----|
               |----B3----|
               |----------B4----------|
               |----------------B5----------------|
                      |----B6----|
----------------------|-------A-------|----------------------
                      |------B7-------|
                      |----------B8-----------|
                         |----B9----|
                         |----B10-----|
                         |--------B11--------|
                                      |----B12----|
                                         |----B13----|
----------------------|-------A-------|----------------------
74
Jonathan Leffler

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) { 
    ...
}
26
Vitalii Fedorenko

Toutes les solutions qui vérifient une multitude de conditions en fonction de la relation entre les plages peuvent être grandement simplifiées par vous 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 gammes si nécessaire à l’avance.

Ensuite, vous pouvez détecter un chevauchement si le début de l'autre plage est inférieur ou égal à la fin de la première plage (si les plages sont inclusives, contenant les heures de début et de fin) ou inférieur à (si les plages incluent le début et exclusive de la fin). .

En supposant que cela soit inclus aux deux extrémités, il n'y a que quatre possibilités, dont l'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 dans:

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 code segment, vous utiliseriez < plutôt que <=):

|----------------------|        range 1
|--->                           range 2 overlap
 |--->                          range 2 overlap
                       |--->    range 2 no overlap
                        |--->   range 2 no overlap

Vous limitez grandement le nombre de vérifications à effectuer car vous supprimez la moitié de l’espace posant problème en vous assurant que la plage 1 ne commence jamais après la plage 2.

17
paxdiablo

Voici encore une autre solution utilisant JavaScript. Spécialités de ma solution:

  • Traite les valeurs nulles comme infini
  • Suppose que la limite inférieure est inclusive et la limite supérieure exclusive.
  • Vient avec un tas de tests

Les tests sont basés sur des entiers, mais comme les objets de date en JavaScript sont comparables, vous pouvez également ajouter deux objets de date. Ou vous pouvez ajouter le timestamp milliseconde.

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);
}

Tests:

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écution de 20 sur 20 SUCCESS (0.003 sec/0.004 sec)

13
yankee

Je ferais

StartDate1.IsBetween(StartDate2, EndDate2) || EndDate1.IsBetween(StartDate2, EndDate2)

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);
    }
9
Bob

Je sais que cela a été étiqueté comme étant indépendant de la langue, mais pour tous ceux qui implémentent en Java: ne réinventez pas la roue et utilisez Joda Time.

http://joda-time.sourceforge.net/api-release/org/joda/time/base/AbstractInterval.html#overlaps (org.joda.time.ReadableInterval )

9
Stefan Haberl

enter image description here

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 -> 1Fin
  • C -> 2Start
  • D -> 2Fin

Preuve? Découvrez ce test code de la console Gist .

8

Voici ma solution dans Java, qui fonctionne aussi sur des intervalles non borné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));
}
7
Khaled.K

La solution publiée ici ne fonctionnait pas pour toutes les gammes qui se chevauchent ...

---------------------- | ------- A ------- | ----------- ----------- 
 | ---- B1 ---- | 
 | ---- B2 ---- | 
 | - --- B3 ---- | 
 | ---------- B4 ---------- | 
 | ------- --------- B5 ---------------- | 
 | ---- B6 ---- | 
 - -------------------- | ------- A ------- | ------------- --------- 
 | ------ B7 ------- | 
 | ---------- B8 --- -------- | 
 | ---- B9 ---- | 
 | ---- B10 ----- | 
 | - ------ B11 -------- | 
 | ---- B12 ---- | 
 | ---- B13 ---- | 
 ---------------------- | ------- A ------- | -------- --------------

ma solution de travail était:

. - prend en compte la date de début et la date de début, extérieure 
 OU 
 (STARTDATE ENTRE 'date_début' ET 'date_fin') - une seule nécessaire pour la plage extérieure contenant les dates. 
) 
6
on_

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;
5
Ignacio Pascual

le plus simple

Le moyen le plus simple consiste à utiliser une bibliothèque dédiée bien conçue pour le travail date-heure.

_someInterval.overlaps( anotherInterval )
_

Java.time & ThreeTen-Extra

Le meilleur du marché est le framework Java.time intégré à Java 8 et versions ultérieures. Ajoutez à cela le projet ThreeTen-Extra qui complète Java.time avec des classes supplémentaires, en particulier la classe Interval dont nous avons besoin ici.

En ce qui concerne la balise _language-agnostic_ de cette Question, le code source des deux projets est disponible pour une utilisation dans d'autres langues (en tenant compte de leurs licences).

Interval

La classe org.threeten.extra.Interval est pratique, mais nécessite des instants date-heure (objets _Java.time.Instant_) 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.

_Interval interval_A = Interval.of( start , stop );
_

Nous pouvons également 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 pour tester les chevauchements est facile.

_Boolean overlaps = interval_A.overlaps( interval_B );
_

Vous pouvez comparer un Interval à un autre Interval ou Instant :

Tous utilisent l’approche _Half-Open_ pour définir une période de temps où le début est inclus et la fin est exclusif .

3
Basil Bourque

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)
2
Tom McDonough

Si vous utilisez une plage de dates qui n'est pas encore terminée (par exemple, par exemple). not set endDate = '0000-00-00' vous ne pouvez pas utiliser BETWEEN car 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 à enddate, il n'y a pas de chevauchement!

2
jack

Ceci est une extension du 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 ssi: (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 ssi: (StartA < EndB) and (EndA > StartB)

Cas 3 : A, B à droite

A = [StartA, EndA)
B = [StartB, EndB)

                         [---- DateRange A ------)   (True if StartA >= EndB) 
[--- Date Range B -----)                           

[---- DateRange A -----)                             (True if EndA <= StartB)
                         [--- Date Range B ----)

État de chevauchement: (StartA < EndB) and (EndA > StartB)

Cas 4 : A, B laissés 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 ----]

État de chevauchement: (StartA < EndB) and (EndA > StartB)

Cas 5 : A 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 ----]

État de chevauchement: (StartA <= EndB) and (EndA > StartB)

etc ...

Enfin, la condition générale de chevauchement de deux intervalles est

(StartA <???? EndB) et (EndA> ???? StartB)

où ???? transforme une inégalité stricte en une non-stricte chaque fois que la comparaison est faite entre deux paramètres inclus.

2
user2314737

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
1
Prasenjit Banerjee

Une solution facile à retenir serait
min(ends)>max(starts)

1
Radacina

La meilleure façon 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.

1
AlexDrenea

En utilisant 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;
    }
1
Shehan Simen

La solution mathématique donnée par @Bretana est bonne mais néglige deux détails spécifiques:

  1. aspect des intervalles fermés ou semi-ouverts
  2. intervalles vides

À propos de l'état fermé ou ouvert des limites d'intervalle, la solution de @Bretana est valide pour les intervalles fermés

(StartA <= EndB) et (EndA> = StartB)

peut être réécrit pour des intervalles semi-ouverts en:

(StartA <EndB) et (EndA> StartB)

Cette correction est nécessaire car une limite d'intervalle ouvert n'appartient pas à la plage de valeurs d'un intervalle par définition.


Et à propos de intervalles vides , eh bien, la relation ci-dessus ne tient pas. Les intervalles vides qui, par définition, ne contiennent aucune valeur valide doivent être traités comme des cas particuliers. 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 crochet principal "[" 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 <endB), donc Time4J (ainsi que d'autres bibliothèques) doit le gérer comme un cas Edge spécial afin de garantir le chevauchement de tout intervalle arbitraire avec un intervalle vide. n'existe pas. Bien entendu, les intervalles de date (qui sont fermés par défaut dans Time4J mais peuvent être semi-ouverts, comme les intervalles de date vides) sont traités de la même manière.

1
Meno Hochschild

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
         */
    }
1
staceyw

Voici encore une autre réponse abrégée utilisant momentjs:

function isOverlapping(startDate1, endDate1, startDate2, endDate2){ 
return moment(startDate1).isSameOrBefore(endDate2) && 
moment(startDate2).isSameOrBefore(endDate1);
}

la réponse est basée sur les réponses ci-dessus, mais est raccourcie.

1
Nitin Jadhav

J'ai eu une situation où nous avions des dates au lieu de dates-heures, et les dates peuvent se chevaucher seulement au début/à la fin. Exemple ci-dessous:

enter image description here

(Le vert est l'intervalle actuel, les blocs bleus sont des intervalles valides, les rouges les 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.

1
Gus
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");
            }
1
mmarjeh

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

Je l'ai trouvé ici avec une explication intéressante -> http://makandracards.com/makandra/984-test-if-two-date-ranges-overlap-in-Ruby-or-Rails

0
mahatmanich
if (StartDate1 > StartDate2) swap(StartDate, EndDate);

(StartDate1 <= EndDate2) and (StartDate2 <= EndDate1);
0
Syam

Divisez le problème en cas puis gérez chaque cas.

La situation "intersection de deux plages de dates" 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.

0
Colonel Panic

Si vous fournissez une plage de dates en tant qu'entrée et souhaitez savoir si elle chevauche la plage de dates existante dans la base de données, les conditions suivantes peuvent répondre à votre demande.

Supposons que vous fournissiez un @StartDate et @EndDate à partir de votre entrée de formulaire.

les conditions sont:

Si @StartDate est en avance sur existingStartDate et derrière existingEndDate, alors nous pouvons dire que @StartDate se trouve au milieu d'une plage de dates existante, nous pouvons donc en conclure qu'il va se chevaucher.

@StartDate >=existing.StartDate And @StartDate <= existing.EndDate) 

Si @StartDate est derrière existingStartDate mais @EndDate est en avance sur existingStartDate on peut dire qu'il va se chevaucher

 (@StartDate <= existing.StartDate And @EndDate >= existing.StartDate)

Si @StartDate est en retard existingStartDate et @EndDate en avance sur existingEndDate, nous pouvons en conclure que la plage de dates fournie dévore une plage de dates existante et se chevauche.

 (@StartDate <= existing.StartDate And @EndDate >= existing.EndDate))

Si l'une des conditions est vraie, la plage de dates fournie chevauche celle qui existe dans la base de données.

0
AL-zami

La requête ci-dessous me donne les identifiants pour lesquels la plage de dates fournie (dates de début et de fin se chevauche avec l'une des dates (dates de début et de fin) de mon nom de table

select id from table_name where (START_DT_TM >= 'END_DATE_TIME'  OR   
(END_DT_TM BETWEEN 'START_DATE_TIME' AND 'END_DATE_TIME'))
0
Shravan Ramamurthy

Solution facile:

compare the two dates: 
    A = the one with smaller start date, B = the one with bigger start date
if(A.end < B.start)
    return false
return true
0
sorry_I_wont

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);
0
Ilya

C'était ma solution, elle retourne true lorsque les valeurs ne se chevauchent pas:

X DÉBUT 1 Y FIN 1

A START 2 B END 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
0
Fez Vrasta