it-swarm.com.de

Bestimmen Sie, ob sich zwei Datumsbereiche überlappen

Was ist bei zwei Datumsbereichen die einfachste oder effizienteste Methode, um festzustellen, ob sich die beiden Datumsbereiche überschneiden?

Angenommen, wir haben Bereiche, die durch DateTime-Variablen StartDate1 bis EndDate1ndStartDate2 bis EndDate2 angegeben sind.

1138
Ian Nelson

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

Beweis:
Lassen Sie ConditionA bedeuten, dass DateRange A vollständig nach DateRange B liegt
_ |---- DateRange A ------| |---Date Range B -----| _
(Wahr, wenn StartA > EndB)

BedingungB soll bedeuten, dass Datumsbereich A vollständig vor Datumsbereich B liegt
|---- DateRange A -----| _ _ |---Date Range B ----|
(Wahr, wenn EndA < StartB)

Dann liegt eine Überlappung vor, wenn weder A noch B wahr sind -
(Wenn ein Bereich weder vollständig nach dem anderen ist,
noch ganz vor dem anderen, dann müssen sie sich überlappen.)

Nun sagt eines von De Morgans Gesetzen Folgendes:

Not (A Or B) <=> Not A And Not B

Was übersetzt bedeutet: (StartA <= EndB) and (EndA >= StartB)


HINWEIS: Dies schließt Bedingungen ein, bei denen sich die Kanten genau überlappen. Wenn Sie das ausschließen möchten,
Ändern Sie die Operatoren >= in > und <= in <


ANMERKUNG 2. Dank @Baodad, siehe dieses Blog , ist die tatsächliche Überlappung am geringsten von:
{endA-startA, endA - startB, endB-startA, endB - startB}

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


NOTIZ 3. Dank @tomosius lautet eine kürzere Version:
DateRangesOverlap = max(start1, start2) < min(end1, end2)
Dies ist eigentlich eine syntaktische Abkürzung für eine längere Implementierung, die zusätzliche Überprüfungen enthält, um sicherzustellen, dass die Startdaten am oder vor dem Enddatum liegen. Ableiten von oben:

Wenn Start- und Enddatum möglicherweise nicht in der richtigen Reihenfolge sind, dh wenn es möglich ist, dass startA > endA oder startB > endB, müssen Sie auch überprüfen, ob sie in der richtigen Reihenfolge sind, dh, Sie müssen zwei hinzufügen Zusätzliche Gültigkeitsregeln:
(StartA <= EndB) and (StartB <= EndA) and (StartA <= EndA) and (StartB <= EndB) oder:
(StartA <= EndB) and (StartA <= EndA) and (StartB <= EndA) and (StartB <= EndB) oder,
(StartA <= Min(EndA, EndB) and (StartB <= Min(EndA, EndB)) oder:
(Max(StartA, StartB) <= Min(EndA, EndB)

Um jedoch Min() und Max() zu implementieren, müssen Sie (aus Gründen der Kürze mit C ternary) codieren:
(StartA > StartB? Start A: StartB) <= (EndA < EndB? EndA: EndB)

2120
Charles Bretana

Ich glaube, es reicht zu sagen, dass sich die beiden Bereiche überschneiden, wenn:

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

Dieser Artikel Time Period Library für .NET beschreibt die Beziehung zweier Zeiträume durch die Aufzählung 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

Betrachten Sie Allens Intervall-Algebra , um über zeitliche Beziehungen (oder andere Intervall-Beziehungen) nachzudenken. Es beschreibt die 13 möglichen Beziehungen, die zwei Intervalle zueinander haben können. Sie können andere Referenzen finden - "Allen Interval" scheint ein operativer Suchbegriff zu sein. Informationen zu diesen Vorgängen finden Sie auch in Snodgrass ' Entwicklung zeitorientierter Anwendungen in SQL (PDF online unter URL verfügbar) sowie in Date, Darwen und Lorentzos Zeitdaten und das relationale Modell (2002) oder Zeit und relationale Theorie: Zeitdatenbanken im relationalen Modell und in SQL (2014; effektiv die zweite Ausgabe von TD & RM).


Die kurze (ish) Antwort lautet: Wenn zwei Datumsintervalle A und B mit Komponenten .start und .end und der Einschränkung .start <= .end gegeben sind, überlappen sich zwei Intervalle, wenn :

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

Sie können die Verwendung von >= vs > und <= vs < Ihren Anforderungen hinsichtlich des Überlappungsgrades anpassen.


ErikE kommentiert:

Sie können nur 13 bekommen, wenn Sie die Dinge lustig zählen ... Ich kann "15 mögliche Beziehungen bekommen, die zwei Intervalle haben können", wenn ich damit verrückt werde. Durch vernünftiges Zählen bekomme ich nur sechs, und wenn Sie sich nicht darum kümmern, ob A oder B zuerst kommt, bekomme ich nur drei (keine Überschneidung, teilweise Überschneidung, eine vollständig innerhalb der anderen). 15 geht so: [vor: vor, start, innerhalb, ende, nach], [start: start, innerhalb, ende, nach], [innerhalb: innerhalb, ende, nach], [ende: ende, nach], [ nachher: ​​nachher].

Ich denke, dass Sie die beiden Einträge "vorher: vorher" und "nachher: ​​nachher" nicht zählen können. Ich könnte 7 Einträge sehen, wenn Sie einige Beziehungen mit ihren Inversen gleichsetzen (siehe das Diagramm in der referenzierten Wikipedia-URL; es hat 7 Einträge, von denen 6 eine andere Inversion haben, wobei Gleiche keine eindeutige Inversion haben). Und ob drei sinnvoll sind, hängt von Ihren Anforderungen ab.

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

Soll auch die Überlappung selbst berechnet werden, können Sie folgende Formel verwenden:

overlap = max(0, min(EndDate1, EndDate2) - max(StartDate1, StartDate2))
if (overlap > 0) { 
    ...
}
26

Alle Lösungen, die eine Vielzahl von Bedingungen überprüfen, basierend auf dem Verhältnis der Bereiche zueinander, können durch nur sicherstellen, dass ein bestimmter Bereich früher beginnt! Sie stellen sicher, dass der erste Bereich früher beginnt ( oder gleichzeitig) durch Tauschen der Bereiche, falls erforderlich, vorab.

Dann können Sie Überlappungen erkennen, wenn der andere Bereichsanfang kleiner oder gleich dem ersten Bereichsende ist (wenn Bereiche einschließlich der Start- und Endzeiten sind) oder kleiner als (wenn Bereiche einschließlich Anfang und ausschließlich des Endes sind). .

Angenommen, es gibt an beiden Enden einschließlich nur vier Möglichkeiten, von denen eine nicht überlappend ist:

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

Der Endpunkt des Bereichs 2 wird nicht eingegeben. Also im Pseudocode:

def doesOverlap (r1, r2):
    if r1.s > r2.s:
        swap r1, r2
    if r2.s > r1.e:
        return false
    return true

Dies könnte noch weiter vereinfacht werden in:

def doesOverlap (r1, r2):
    if r1.s > r2.s:
        swap r1, r2
    return r2.s <= r1.e

Wenn die Bereiche am Anfang inklusive und am Ende exklusiv sind, müssen Sie nur > durch >= in der zweiten if -Anweisung ersetzen (für das erste Codesegment: im zweiten Code) Segment, würden Sie < anstelle von <=) verwenden:

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

Sie begrenzen die Anzahl der durchzuführenden Überprüfungen erheblich, da Sie die Hälfte des Problembereichs frühzeitig entfernen, indem Sie sicherstellen, dass Bereich 1 niemals nach Bereich 2 beginnt.

17
paxdiablo

Hier ist noch eine andere Lösung mit JavaScript. Besonderheiten meiner Lösung:

  • Behandelt Nullwerte als unendlich
  • Angenommen, die Untergrenze ist inklusive und die Obergrenze exklusiv.
  • Kommt mit einer Reihe von Tests

Die Tests basieren auf Ganzzahlen, aber da Datumsobjekte in JavaScript vergleichbar sind, können Sie auch zwei Datumsobjekte einfügen. Oder Sie werfen den Millisekunden-Zeitstempel ein.

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

Ergebnis beim Laufen mit Karma & Jasmin & PhantomJS:

PhantomJS 1.9.8 (Linux): 20 von 20 ERFOLGEN ausgeführt (0,003 Sekunden/0,004 Sekunden)

13
yankee

Würde ich tun

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

Wo IsBetween ist so etwas wie

    public static bool IsBetween(this DateTime value, DateTime left, DateTime right) {
        return (value > left && value < right) || (value < left && value > right);
    }
9
Bob

Ich weiß, dass dies als sprachunabhängig eingestuft wurde, aber für Sie alle, die Java implementieren: Erfinden Sie das Rad nicht neu und verwenden Sie 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

Hier ist der Code, der die Magie bewirkt:

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

Wo..

  • A -> 1Start
  • B -> 1End
  • C -> 2Start
  • D -> 2End

Beweis? Schauen Sie sich diesen Test an Konsolencode Gist .

8

Hier ist meine Lösung in Java, die auch für unbegrenzte Intervalle funktioniert

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

Die hier angegebene Lösung hat nicht für alle überlappenden Bereiche funktioniert ...

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

meine Arbeitslösung war:

 AND (
 ('Start_date' zwischen startdatum und enddatum) - Gibt das innere und das äußere Enddatum an. 
 OR 
 ('End_date' zwischen startdatum und enddatum) - für inneres und Startdatum äußeres 
 ODER 
 (STARTDATUM ZWISCHEN 'start_date' UND 'end_date') - nur eines für den äußeren Bereich, in dem Datumsangaben enthalten sind. 
) 
6
on_

Dies war meine Javascript-Lösung mit 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

das einfachste

Am einfachsten ist es, eine ausgereifte Bibliothek für die Datums- und Uhrzeitanzeige zu verwenden.

_someInterval.overlaps( anotherInterval )
_

Java.time & ThreeTen-Extra

Das Beste im Geschäft ist das in Java 8 und höher integrierte Java.time Framework. Fügen Sie dazu das ThreeTen-Extra -Projekt hinzu, das Java.time um zusätzliche Klassen ergänzt, insbesondere die Interval -Klasse, die wir hier benötigen.

Für das _language-agnostic_ -Tag in dieser Frage steht der Quellcode für beide Projekte zur Verwendung in anderen Sprachen zur Verfügung (beachten Sie deren Lizenzen).

Interval

Die Klasse org.threeten.extra.Interval ist praktisch, erfordert jedoch Datum-Uhrzeit-Momente (_Java.time.Instant_ -Objekte) und keine Datumswerte. Daher verwenden wir den ersten Moment des Tages in UTC, um das Datum darzustellen.

_Instant start = Instant.parse( "2016-01-01T00:00:00Z" );
Instant stop = Instant.parse( "2016-02-01T00:00:00Z" );
_

Erstellen Sie eine Interval, um diese Zeitspanne darzustellen.

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

Wir können auch ein Interval mit einem Startzeitpunkt plus einem Duration definieren.

_Instant start_B = Instant.parse( "2016-01-03T00:00:00Z" );
Interval interval_B = Interval.of( start_B , Duration.of( 3 , ChronoUnit.DAYS ) );
_

Das Vergleichen mit dem Testen auf Überlappungen ist einfach.

_Boolean overlaps = interval_A.overlaps( interval_B );
_

Sie können ein Interval mit einem anderen Interval oder Instant vergleichen:

Alle verwenden den Ansatz _Half-Open_, um eine Zeitspanne zu definieren, in der der Anfang einschließlich und das Ende ausschließlich ist. ).

3
Basil Bourque

Die Antwort ist zu einfach für mich, deshalb habe ich eine allgemeinere dynamische SQL-Anweisung erstellt, die prüft, ob eine Person überlappende Daten hat.

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

Falls Sie einen Datumsbereich verwenden, der noch nicht beendet ist (noch nicht abgeschlossen), z. not set endDate = '0000-00-00' Sie können BETWEEN nicht verwenden, da 0000-00-00 kein gültiges Datum ist!

Ich habe diese Lösung benutzt:

(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

Wenn startdate2 höher als enddate ist, gibt es keine Überlappung!

2
jack

Dies ist eine Erweiterung des ausgezeichnete Antwort von @ charles-bretana.

Die Antwort unterscheidet jedoch nicht zwischen offenen, geschlossenen und halboffenen (oder halbgeschlossenen) Intervallen.

Fall 1 : A, B sind geschlossene Intervalle

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

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


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

Überlappung iff: (StartA <= EndB) and (EndA >= StartB)

Fall 2 : A, B sind offene Intervalle

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

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

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

Überlappung iff: (StartA < EndB) and (EndA > StartB)

Fall 3 : A, B rechts offen

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

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

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

Überlappungsbedingung: (StartA < EndB) and (EndA > StartB)

Fall 4 : A, B offen gelassen

A = (StartA, EndA]
B = (StartB, EndB]

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

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

Überlappungsbedingung: (StartA < EndB) and (EndA > StartB)

Fall 5 : A rechts offen, B geschlossen

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

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


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

Überlappungsbedingung: (StartA <= EndB) and (EndA > StartB)

etc ...

Schließlich ist die allgemeine Bedingung für zwei überlappende Intervalle

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

wo ???? Verwandelt eine strenge Ungleichung in eine nichtstrenge, wenn der Vergleich zwischen zwei eingeschlossenen Endpunkten durchgeführt wird.

2
user2314737

In Microsoft SQL SERVER - SQL-Funktion

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

Eine leicht zu merkende Lösung wäre
min(ends)>max(starts)

1
Radacina

Meiner Meinung nach ist es am einfachsten zu vergleichen, ob EndDate1 vor StartDate2 und EndDate2 vor StartDate1 liegt.

Dies gilt natürlich, wenn Sie Intervalle berücksichtigen, bei denen StartDate immer vor EndDate liegt.

1
AlexDrenea

Mit Java util.Date, hier was ich getan habe.

    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

Die mathematische Lösung von @Bretana ist gut, vernachlässigt jedoch zwei spezifische Details:

  1. aspekt der geschlossenen oder halboffenen Intervalle
  2. leere Intervalle

Über den geschlossenen oder offenen Zustand von Intervallgrenzen gilt die Lösung von @Bretana für geschlossene Intervalle

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

kann umgeschrieben werden für halboffene Intervalle bis:

(StartA <EndB) und (EndA> StartB)

Diese Korrektur ist notwendig, da eine offene Intervallgrenze per Definition nicht zum Wertebereich eines Intervalls gehört.


Und ungefähr leere Intervalle, hier gilt die oben gezeigte Beziehung NICHT. Leere Intervalle, die per Definition keinen gültigen Wert enthalten, müssen als Sonderfall behandelt werden. Ich demonstriere es mit meiner Java Zeitbibliothek Time4J anhand des folgenden Beispiels:

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)

Die vordere eckige Klammer "[" kennzeichnet einen geschlossenen Anfang, während die letzte Klammer ")" ein offenes Ende kennzeichnet.

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

Wie oben gezeigt, verletzen leere Intervalle die oben angegebene Überlappungsbedingung (insbesondere startA <endB), sodass Time4J (und auch andere Bibliotheken) diese als speziellen Edge-Fall behandeln müssen, um sicherzustellen, dass sich ein beliebiges Intervall mit einem leeren Intervall überlappt ist nicht vorhanden. Natürlich werden Datumsintervalle (die in Time4J standardmäßig geschlossen sind, aber auch halboffen sein können, wie leere Datumsintervalle) auf ähnliche Weise behandelt.

1
Meno Hochschild

Hier ist eine generische Methode, die lokal nützlich sein kann.

    // 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

Hier ist noch eine verkürzte Antwort mit momentjs:

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

die Antwort basiert auf den obigen Antworten, ist aber gekürzt.

1
Nitin Jadhav

Ich hatte eine Situation, in der wir Daten anstelle von Datumsangaben hatten und die Daten sich nur am Anfang/Ende überlappen konnten. Beispiel unten:

enter image description here

(Grün ist das aktuelle Intervall, blaue Blöcke sind gültige Intervalle, rote überlappende Intervalle).

Ich habe die Antwort von Ian Nelson an die folgende Lösung angepasst:

   (startB <= startA && endB > startA)
|| (startB >= startA && startB < endA)

Dies stimmt mit allen Überlappungsfällen überein, ignoriert jedoch die zulässigen Überlappungsfälle.

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

Für Ruby habe ich auch folgendes gefunden:

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

Fand es hier mit netter Erklärung -> 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

Teilen Sie das Problem in Fälle auf und behandeln Sie dann jeden Fall.

Die Situation, dass sich zwei Datumsbereiche überschneiden, wird durch zwei Fälle abgedeckt: Der erste Datumsbereich beginnt innerhalb des zweiten Datumsbereichs oder der zweite Datumsbereich beginnt innerhalb des ersten Datumsbereichs.

0
Colonel Panic

Wenn Sie einen Datumsbereich als Eingabe angeben und herausfinden möchten, ob dieser mit dem vorhandenen Datumsbereich in der Datenbank überlappt, können die folgenden Bedingungen Ihren Bedarf erfolgreich decken

Angenommen, Sie geben @StartDate und @EndDate in Ihre Formulareingabe ein.

Bedingungen sind:

Wenn @StartDate vor existingStartDate und hinter existingEndDate steht, können wir sagen, dass @StartDate sich in der Mitte eines vorhandenen Datumsbereichs befindet, sodass wir davon ausgehen können, dass sich dieser überschneidet

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

Wenn @StartDate hinter existingStartDate liegt, aber @EndDate vor existingStartDate, können wir sagen, dass es sich überlappt

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

Wenn @StartDate hinter existingStartDate und @EndDate vor existingEndDate liegt, können wir daraus schließen, dass der angegebene Datumsbereich einen vorhandenen Datumsbereich verschlingt und sich somit überschneidet

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

Wenn eine der Bedingungen zutrifft, überschneidet sich der angegebene Datumsbereich mit den in der Datenbank vorhandenen.

0
AL-zami

Die folgende Abfrage gibt mir die IDs, für die sich der angegebene Datumsbereich (Start- und Enddatum) mit einem beliebigen Datum (Start- und Enddatum) in meinem Tabellennamen überschneidet

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

Einfache Lösung:

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

Sie können dies versuchen:

//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

Dies war meine Lösung. Sie gibt true zurück, wenn sich die Werte nicht überschneiden:

X START 1 Y ENDE 1

A START 2 B ENDE 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