Angenommen, wir haben Bereiche, die durch DateTime-Variablen StartDate1
bis EndDate1
und StartDate2
bis EndDate2
bezeichnet sind.
Auf jeden Fall können wir die tatsächliche Anzahl der Überlappungssekunden erhalten
Angenommen, wir haben Bereiche, die durch DateTime-Variablen StartDate1
bis EndDate1
und StartDate2
bis EndDate2
bezeichnet sind.
(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)
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
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 ;)
Ich finde die (StartDate1 <= EndDate2) und (EndDate1 >= StartDate2)
Notation einfacher zu verstehen, Range1 ist immer links in den Tests.
Dies setzt voraus, dass Start- und Enddaten inklusive sind. Ändern Sie <=
in <
, wenn der Start inklusive ist und das Ende exklusiv ist.
Dies funktioniert auch sehr gut, selbst wenn startDate2 vor startDate1 liegt. Also muss man nicht annehmen, dass startDate1 früher ist als startDate2.
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
Schön, ich habe auch Allens Intervallalgebra in Java implementiert, siehe die API von IntervalRelation und IsoInterval
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-------|----------------------
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].
@Emtucifor: Ich glaube, dass du die beiden Einträge 'before:before' und 'after:after' nicht zählen kannst.
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!
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.
3 Stimmen
Äußerst ähnlich wie stackoverflow.com/questions/306316/…
1 Stimmen
@CharlesBretana Vielen Dank dafür, du hast Recht - das ist fast wie eine zweidimensionale Version meiner Frage!
2 Stimmen
Sehr ähnlich wie stackoverflow.com/questions/117962/…
2 Stimmen
Teile die Situation "Die beiden Datumsbereiche überschneiden sich" in Fälle (es gibt zwei) und teste dann jeweils für jeden Fall.
0 Stimmen
Ich weiß, dass dies als sprachunabhängig markiert wurde, aber für alle, die in Java implementieren: Erfinden Sie das Rad nicht neu und verwenden Sie Joda Time. joda-time.sourceforge.net/api-release/org/joda/time/base/…
0 Stimmen
Wenn Daten NULL-Werte (oder leer) sein können, wenn sie nicht festgelegt sind, gibt es diese Frage, die eine Erweiterung dieser ist.
0 Stimmen
Algorithmus zum Zusammenführen überlappender Intervalle kann einige Hinweise geben.
1 Stimmen
Hallo.. A: StartDate1, B: EndDate1, C: StartDate2, D: EndDate2. Wenn B < C oder A > D, dann nehmen wir an, dass sie sich nicht überschneiden.. Also können wir einfach mit "isintersects = not (B < C oder A > D)" testen, ob es sich überschneidet oder nicht.
0 Stimmen
Noch ein Intervallhilfsprogramm für .Net github.com/AlexeyBoiko/IntervalUtility (Ich bin der Autor)