1651 Stimmen

Bestimmen Sie, ob sich zwei Datumsbereiche überschneiden.

Angenommen, wir haben Bereiche, die durch DateTime-Variablen StartDate1 bis EndDate1 und StartDate2 bis EndDate2 bezeichnet sind.

3 Stimmen

1 Stimmen

@CharlesBretana Vielen Dank dafür, du hast Recht - das ist fast wie eine zweidimensionale Version meiner Frage!

2 Stimmen

2991voto

Charles Bretana Punkte 137391

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

Beweis:
Nehmen wir an, Bedingung A bedeutet, dass der Datumsbereich A vollständig nach dem Datumsbereich B liegt

_                        |---- Datumsbereich A ------|
|---Datumsbereich B -----|                          _

(Wahr, wenn StartA > EndB)

Nehmen wir an, Bedingung B bedeutet, dass der Datumsbereich A vollständig vor dem Datumsbereich B liegt

|---- Datumsbereich A -----|                        _ 
_                          |---Datumsbereich B ----|

(Wahr, wenn EndA < StartB)

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

Nun besagt eines von De Morgan's laws:

Nicht (A Oder B) <=> Nicht A Und Nicht B

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


HINWEIS: Dies beinhaltet Bedingungen, bei denen die Ränder genau überlappen. Wenn Sie das ausschließen möchten,
ändern Sie die >= Operatoren in > um, und <= in <


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

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


HINWEIS3. Dank an @tomosius, eine kürzere Version lautet:
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 zu überprüfen, dass die Startdaten auf oder vor den Enddaten liegen. Abgeleitet aus obigem:

Wenn Start- und Enddaten in umgekehrter Reihenfolge sein können, d.h., wenn es möglich ist, dass startA > endA oder startB > endB ist, müssen Sie auch überprüfen, ob sie in der richtigen Reihenfolge sind. Das bedeutet, dass Sie zwei zusätzliche Gültigkeitsregeln hinzufügen müssen:
(StartA <= EndB) und (StartB <= EndA) und (StartA <= EndA) und (StartB <= EndB) oder:
(StartA <= EndB) und (StartA <= EndA) und (StartB <= EndA) und (StartB <= EndB) oder:
(StartA <= Min(EndA, EndB) und (StartB <= Min(EndA, EndB)) or:
(Max(StartA, StartB) <= Min(EndA, EndB)

Aber um Min() und Max() zu implementieren, müssen Sie codieren (mit C-Ternary für Kürze):
((StartA > StartB) ? StartA : StartB) <= ((EndA < EndB) ? EndA : EndB)

0 Stimmen

Auf jeden Fall können wir die tatsächliche Anzahl der Überlappungssekunden erhalten

0 Stimmen

Ja, aber ich denke nicht, dass es einen einfachen Weg gibt... Ohne tatsächliches SQL zu schreiben, wäre ein Algorithmus: Verwendung von A0, A1, B0 und B1 als Punkte: Wenn kein Überlappung, dann 0; Wenn B0 und B1 beide zwischen A0 und A1 liegen, dann ist es B1-B0; Wenn nur B0 zwischen A0 und A1 liegt, dann ist es A1-B0; wenn nur B1 zwischen A0 und A1 liegt, dann ist es B1-A0; sonst ist es A1-A0

61 Stimmen

Dies ist eine vereinfachte Logik, die auf diesen beiden Annahmen basiert: 1) StartA < EndA; 2) StartB < EndB. Es scheint offensichtlich zu sein, aber in der Realität können Daten aus unbekannten Quellen wie Benutzereingaben oder einer Datenbank ohne Säuberung stammen. Denken Sie daran, dass Sie die Eingabedaten validieren müssen, um sicherzustellen, dass diese beiden Annahmen wahr sind, bevor Sie diese vereinfachte Logik verwenden können, oder alles wird auseinanderfallen. Eine Lektion, die ich aus meiner eigenen Erfahrung gelernt habe ;)

551voto

Ian Nelson Punkte 53679

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

(StartDate1 <= EndDate2) und (StartDate2 <= EndDate1)

113 Stimmen

Ich finde die (StartDate1 <= EndDate2) und (EndDate1 >= StartDate2) Notation einfacher zu verstehen, Range1 ist immer links in den Tests.

20 Stimmen

Dies setzt voraus, dass Start- und Enddaten inklusive sind. Ändern Sie <= in <, wenn der Start inklusive ist und das Ende exklusiv ist.

0 Stimmen

Dies funktioniert auch sehr gut, selbst wenn startDate2 vor startDate1 liegt. Also muss man nicht annehmen, dass startDate1 früher ist als startDate2.

173voto

Dieser Artikel Zeitperiodenbibliothek für .NET beschreibt die Beziehung von zwei Zeitperioden anhand der Aufzählung PeriodRelation:

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

Bildbeschreibung hier eingeben

0 Stimmen

Schön, ich habe auch Allens Intervallalgebra in Java implementiert, siehe die API von IntervalRelation und IsoInterval

4 Stimmen

Tolle Zusammenfassung, um Spezifikationen für sich überschneidende Daten zu schreiben

107voto

Jonathan Leffler Punkte 694013

Für Überlegungen zu zeitlichen Beziehungen (oder zu anderen Intervallbeziehungen) könnte Allens Intervallalgebra von Interesse sein. Es beschreibt die 13 möglichen Beziehungen, die zwei Intervalle zueinander haben können. Weitere Referenzen finden Sie unter dem Suchbegriff „Allen Intervall“. Informationen zu diesen Operationen finden Sie auch bei Snodgrass in Die Programmierung zeitbezogener Anwendungen in SQL (PDF online verfügbar unter der URL), und bei Date, Darwen und Lorentzos in Zeitdaten und das relationale Modell (2002) oder in Zeit und Relationale Theorie: Zeitliche Datenbanken im relationalen Modell und SQL (2014; effektiv die zweite Ausgabe von TD&RM).


Die kurze (in etwa) Antwort ist: Gegeben zwei Datumsintervalle A und B mit den Komponenten .start und .end sowie der Einschränkung .start <= .end, dann überlappen sich zwei Intervalle, wenn:

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

Sie können die Verwendung von >= vs > und <= vs < anpassen, um Ihre Anforderungen an den Überlappungsgrad zu erfüllen.


ErikE kommentiert:

Sie kommen nur auf 13, wenn Sie die Dinge seltsam zählen... Ich komme auf "15 mögliche Beziehungen, die zwei Intervalle haben können", wenn ich etwas verrückt werde. Durch vernünftiges Zählen erhalte ich nur sechs, und wenn Sie darauf verzichten, ob A oder B zuerst kommt, erhalte ich nur drei (keine Überschneidung, teilweise Überschneidung, eines vollständig im anderen). 15 wäre so: [before:before, start, within, end, after], [start:start, within, end, after], [within:within, end, after], [end:end, after], [after:after].

Ich denke, dass die beiden Einträge 'before:before' und 'after:after' nicht gezählt werden können. Ich könnte 7 Einträge sehen, wenn Sie bestimmte Beziehungen mit ihren Inversen gleichsetzen (siehe das Diagramm unter der in der referenzierten Wikipedia-URL; es enthält 7 Einträge, von denen 6 ein unterschiedliches Inverses haben, wobei Gleichheit kein eigenständiges Inverses hat). 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-------|----------------------

1 Stimmen

Du kannst nur 13 bekommen, wenn du Dinge lustig zählst... Ich kann "15 mögliche Beziehungen, die zwei Intervalle haben können" bekommen, wenn ich verrückt werde. Durch vernünftiges Zählen erhalte ich nur sechs und wenn es dir egal ist, ob A oder B zuerst kommt, erhalte ich nur drei (keine Schnittpunkte, teilweise Schnittpunkte, eine vollständig innerhalb der anderen). 15 geht so: [vorher:vorher, Anfang, innerhalb, Ende, nachher], [Anfang:Anfang, innerhalb, Ende, nachher], [innerhalb:innerhalb, Ende, nachher], [Ende:Ende, nachher], [nachher:nachher].

0 Stimmen

@Emtucifor: Ich glaube, dass du die beiden Einträge 'before:before' und 'after:after' nicht zählen kannst.

0 Stimmen

Ihre Aktualisierung: B1 zu A ist before:before und B13 zu A ist after:after. Ihr schönes Diagramm fehlt Start:start zwischen B5 B6 und End:end zwischen B11 und B12. Wenn es wichtig ist, auf einem Endpunkt zu sein, dann müssen Sie es zählen, also beträgt das Endergebnis 15, nicht 13. Ich persönlich denke, dass die Sache mit dem Endpunkt nicht wichtig ist, also zähle ich es [before: before, innerhalb, after], [innerhalb: innerhalb, after], [after:after], was auf 6 kommt. Ich denke, das Ganze mit dem Endpunkt ist nur Verwirrung darüber, ob die Grenzen inklusiv oder exklusiv sind. Die Exklusivität der Endpunkte ändert nicht die Kernbeziehungen!

40voto

Vitalii Fedorenko Punkte 103468

Wenn der Überlapp selbst ebenfalls berechnet werden soll, können Sie die folgende Formel verwenden:

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

0 Stimmen

So überschneidet sich die zeit, die die beiden ereignisse gemeinsam haben? Funktioniert das für alle verschiedenen arten von überschneidungen von ereignissen?

2 Stimmen

Dies funktioniert nicht, wenn es eine vollständige Überlappung gibt. Zum Beispiel Bereich1: 1-7 Bereich2: 4-5

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X