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.

1008
demandé sur David Faber 2008-11-28 17:48:35

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)

1913
répondu Charles Bretana 2017-02-09 13:46:01

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

(StartDate1 <= EndDate2) and (StartDate2 <= EndDate1)
328
répondu Ian Nelson 2008-11-28 15:01:25

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

entrez la description de l'image ici

92
répondu 2014-05-29 08:03:33

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-------|----------------------
68
répondu Jonathan Leffler 2017-08-21 07:44:31

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) { 
    ...
}
25
répondu Vitalii Fedorenko 2012-09-06 02:07:10

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.

16
répondu paxdiablo 2012-12-17 09:00:11

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)

13
répondu yankee 2015-03-13 13:19:48

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.

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

8
répondu Stefan Haberl 2012-10-13 15:10:59

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);
    }
7
répondu Bob 2016-07-27 14:09:53

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.
) 
5
répondu on_ 2013-11-05 08:24:53

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));
}
5
répondu Khaled.K 2017-10-05 09:11:24

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;
4
répondu Ignacio Pascual 2013-09-12 20:28:36

entrez la description de l'image ici

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 .

4
répondu sandeep talabathula 2017-10-28 18:52:24

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!

2
répondu jack 2014-03-27 17:12:30

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.

2
répondu Basil Bourque 2016-11-04 23:30:07

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.

2
répondu user2314737 2017-06-14 19:06:23

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
répondu staceyw 2009-04-13 05:14:50

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
répondu Prasenjit Banerjee 2014-07-05 13:49:48
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
répondu mmarjeh 2014-07-18 17:12:05

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;
    }
1
répondu Shehan Simen 2015-02-06 05:21:51

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.

1
répondu AlexDrenea 2016-10-19 14:10:52

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:

entrez la description de l'image ici

(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.

1
répondu Gus 2017-01-18 15:46:58

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

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

1
répondu Meno Hochschild 2017-04-10 05:56:52
if (StartDate1 > StartDate2) swap(StartDate, EndDate);

(StartDate1 <= EndDate2) and (StartDate2 <= EndDate1);
0
répondu Syam 2012-01-23 07:23:20

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.

0
répondu Colonel Panic 2012-10-12 23:17:53

, 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
répondu Ilya 2014-03-25 14:02:53

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
0
répondu Fez Vrasta 2014-11-27 15:26:41

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

0
répondu mahatmanich 2015-10-24 23:40:45

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'))
0
répondu Shravan Ramamurthy 2016-01-19 21:57:31

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)
0
répondu Tom McDonough 2016-12-09 16:16:33