Was ist bei zwei Datumsbereichen der einfachste oder effizienteste Weg, um festzustellen, ob sich die beiden Datumsbereiche überschneiden?
Angenommen, wir haben Bereiche, die mit DateTime-Variablen StartDate1
to EndDate1
und StartDate2
to gekennzeichnet sind EndDate2
.
datetime
math
language-agnostic
Ian Nelson
quelle
quelle
Antworten:
(StartA <= EndB) und (EndA> = StartB)
Beweis:
Lassen Sie Bedingung A bedeuten, dass DateRange A vollständig nach DateRange B liegt
_ |---- DateRange A ------| |---Date Range B -----| _
(True if
StartA > EndB
)ConditionB bedeutet, dass DateRange A vollständig vor DateRange B liegt
|---- DateRange A -----| _ _ |---Date Range B ----|
(True if
EndA < StartB
)Dann besteht eine Überlappung, wenn weder A noch B wahr sind -
(Wenn ein Bereich weder vollständig nach dem anderen
noch vollständig vor dem anderen liegt, müssen sie sich überlappen.)
Nun besagt eines von De Morgans Gesetzen :
Not (A Or B)
<=>Not A And Not B
Was bedeutet:
(StartA <= EndB) and (EndA >= StartB)
HINWEIS: Dies schließt Bedingungen ein, bei denen sich die Kanten genau überlappen. Wenn Sie dies ausschließen möchten,
ändern Sie die
>=
Operatoren in>
und<=
in<
ANMERKUNG 2. Dank @Baodad finden Sie in diesem Blog , die tatsächliche Überlappung ist am wenigsten:
{
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 Verknüpfung für eine längere Implementierung, die zusätzliche Überprüfungen enthält, um zu überprüfen, ob die Startdaten am oder vor den Enddaten liegen. Ableiten von oben:
Wenn Start- und Enddaten nicht in Ordnung sein können, dh wenn es möglich ist, dass
startA > endA
oderstartB > endB
, dann müssen Sie auch überprüfen, ob sie in Ordnung sind, was bedeutet, dass Sie zwei zusätzliche Gültigkeitsregeln hinzufügen müssen:(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)
Aber um zu implementieren
Min()
undMax()
, müssen Sie codieren (mit C ternary für die Knappheit):(StartA > StartB? Start A: StartB) <= (EndA < EndB? EndA: EndB)
quelle
Start
und BedeutungenEnd
. Wenn Sie zwei Variablen mit den Namen Top und Bottom oder East and West oder HighValue und LoValue haben, kann davon ausgegangen oder impliziert werden, dass irgendwo etwas oder jemand sicherstellen sollte, dass eines der Wertepaare nicht in den entgegengesetzten Variablen gespeichert wird. -Nur eines der beiden Paare, da es auch funktioniert, wenn beide Wertepaare vertauscht werden.start
undend
(mit der Semantik "null start" = "Vom Anfang der Zeit" und "null end" = "Bis zum Ende der Zeit") wie(startA === null || endB === null || startA <= endB) && (endA === null || startB === null || endA >= startB)
DateRangesOverlap = max(start1, start2) < min(end1, end2)
Ich glaube, es reicht zu sagen, dass sich die beiden Bereiche überschneiden, wenn:
quelle
(StartDate1 <= EndDate2) and (EndDate1 >= StartDate2)
Notation leichter zu verstehen, Range1 ist in den Tests immer links.<=
zu,<
wenn Start inklusive und Ende exklusiv ist.Dieser Artikel Time Period Library für .NET beschreibt die Beziehung zweier Zeiträume durch die Aufzählung PeriodRelation :
quelle
Betrachten Sie Allens Intervallalgebra , um über zeitliche Beziehungen (oder andere Intervallbeziehungen) 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 Operationen finden Sie auch in Snodgrass ' Entwicklung zeitorientierter Anwendungen in SQL (PDF online verfügbar unter URL) sowie in Datums-, Darwen- und Lorentzos- Zeitdaten und dem relationalen Modell (2002) oder Zeit- und relationale Theorie: Zeitliche Datenbanken in das relationale Modell und SQL (2014; effektiv die zweite Ausgabe von TD & RM).
Die kurze (ish) Antwort lautet: Bei zwei Datumsintervallen
A
undB
mit Komponenten.start
und.end
und der Einschränkung.start <= .end
überlappen sich zwei Intervalle, wenn:Sie können die Verwendung von
>=
vs>
und<=
vs<
anpassen, um Ihre Anforderungen an den Grad der Überlappung zu erfüllen.ErikE kommentiert:
Ich denke, dass Sie die beiden Einträge 'vor: vor' und 'nach: nach' nicht zählen können. Ich könnte 7 Einträge sehen, wenn Sie einige Beziehungen mit ihren Umkehrungen gleichsetzen (siehe das Diagramm in der referenzierten Wikipedia-URL; es enthält 7 Einträge, von denen 6 eine andere Umkehrung haben, wobei Gleichungen keine eindeutige Umkehrung haben). Und ob drei sinnvoll sind, hängt von Ihren Anforderungen ab.
quelle
Wenn die Überlappung selbst ebenfalls berechnet werden soll, können Sie die folgende Formel verwenden:
quelle
Alle Lösungen, die eine Vielzahl von Bedingungen basierend auf der Beziehung der Bereiche zueinander prüfen, können erheblich vereinfacht werden, indem nur sichergestellt wird, dass ein bestimmter Bereich früher beginnt! Sie stellen sicher, dass der erste Bereich früher (oder gleichzeitig) beginnt, indem Sie die Bereiche bei Bedarf im Voraus austauschen.
Dann können Sie eine Überlappung erkennen, wenn der Start des anderen Bereichs kleiner oder gleich dem ersten Bereichsende ist (wenn Bereiche inklusive sind und sowohl die Start- als auch die Endzeit enthalten) oder kleiner als (wenn Bereiche Start und Exklusiv enthalten). .
Unter der Annahme, dass an beiden Enden inklusive ist, gibt es nur vier Möglichkeiten, von denen eine nicht überlappt:
Der Endpunkt des Bereichs 2 wird nicht eingegeben. Also im Pseudocode:
Dies könnte noch weiter vereinfacht werden in:
Wenn die Bereiche am Anfang und exklusiv am Ende inklusive sind, müssen Sie nur ersetzen
>
mit>=
in der zweitenif
Anweisung (für das erste Codesegment: im zweiten Codesegment, dann würden Sie verwenden ,<
anstatt<=
):Sie begrenzen die Anzahl der durchzuführenden Überprüfungen erheblich, da Sie die Hälfte des Problemraums frühzeitig entfernen, indem Sie sicherstellen, dass Bereich 1 niemals nach Bereich 2 beginnt.
quelle
Hier ist noch eine andere Lösung mit JavaScript. Besonderheiten meiner Lösung:
Die Tests basieren auf ganzen Zahlen, aber da Datumsobjekte in JavaScript vergleichbar sind, können Sie auch nur zwei Datumsobjekte einwerfen. Oder Sie werfen den Millisekunden-Zeitstempel ein.
Code:
Tests:
Ergebnis beim Ausführen mit Karma & Jasmin & PhantomJS:
quelle
Ich würde es tun
Wo
IsBetween
ist so etwasquelle
Hier ist der Code, der die Magie macht:
Wo..
Beweis? Schauen Sie sich diesen Testkonsolencode an .
quelle
Hier ist meine Lösung in Java , die auch in unbegrenzten Intervallen funktioniert
quelle
!startA.after(endB)
bedeutet startA <= endB und!endA.before(startB)
bedeutet startB <= endA. Dies sind die Kriterien für ein geschlossenes Intervall und kein offenes Intervall.endB == null
undstartA == null
auf ein offenes Intervall prüfen.endB == null
,startA == null
,endA == null
UndstartB == null
sind alle Kriterien für ein unbeschränktes Intervall zu überprüfen und nicht ein offenes Intervall. Beispiel für die Unterschiede zwischen unbegrenzten und offenen Intervallen: (10, 20) und (20, null) sind zwei offene Intervalle, die sich nicht überlappen. Der letzte hat ein unbegrenztes Ende. Ihre Funktion wird true zurückgeben, aber die Intervalle überschneiden sich nicht, da die Intervalle keine 20 enthalten. (Der Einfachheit halber werden anstelle von Zeitstempeln Zahlen verwendet)Die hier veröffentlichte Lösung funktionierte nicht für alle überlappenden Bereiche ...
Meine Arbeitslösung war:
quelle
Dies war meine Javascript-Lösung mit moment.js:
quelle
Eine einfache Möglichkeit, sich an die Lösung zu erinnern, wäre
min(ends)>max(starts)
quelle
In Microsoft SQL Server - SQL-Funktion
quelle
Am einfachsten ist es, eine ausgereifte Bibliothek für Datums- und Uhrzeitarbeiten zu verwenden.
java.time & ThreeTen-Extra
Das Beste im Geschäft ist das
java.time
in Java 8 und höher integrierte Framework. Fügen Sie dazu das ThreeTen-Extra- Projekt hinzu, das java.time durch zusätzliche Klassen ergänzt, insbesondere dieInterval
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
org.threeten.extra.Interval
Klasse ist praktisch, erfordert jedoch Datums- und Uhrzeitmomente (java.time.Instant
Objekte) anstelle von Nur-Datum-Werten. Wir verwenden also den ersten Moment des Tages in UTC, um das Datum darzustellen.Erstellen Sie eine
Interval
, um diese Zeitspanne darzustellen.Wir können auch ein
Interval
mit einem Startmoment plus a definierenDuration
.Der Vergleich mit dem Testen auf Überlappungen ist einfach.
Sie können eine mit einer
Interval
anderen vergleichenInterval
oderInstant
:abuts
contains
encloses
equals
isAfter
isBefore
overlaps
Alle diese verwenden den
Half-Open
Ansatz, um eine Zeitspanne zu definieren, in der der Anfang inklusive und das Ende exklusiv ist .quelle
Dies ist eine Erweiterung der hervorragenden Antwort von @ charles-bretana.
Die Antwort unterscheidet jedoch nicht zwischen offenen, geschlossenen und halboffenen (oder halbgeschlossenen) Intervallen.
Fall 1 : A, B sind geschlossene Intervalle
Überlappung iff:
(StartA <= EndB) and (EndA >= StartB)
Fall 2 : A, B sind offene Intervalle
Überlappung iff:
(StartA < EndB) and (EndA > StartB)
Fall 3 : A, B rechts offen
Überlappungsbedingung:
(StartA < EndB) and (EndA > StartB)
Fall 4 : A, B offen gelassen
Überlappungsbedingung:
(StartA < EndB) and (EndA > StartB)
Fall 5 : A rechts offen, B geschlossen
Überlappungsbedingung:
(StartA <= EndB) and (EndA > StartB)
usw...
Schließlich ist die allgemeine Bedingung für die Überlappung zweier Intervalle
(StartA <🞐 EndB) und (EndA> 🞐 StartB)
wobei 🞐 eine strikte Ungleichung in eine nicht strenge Ungleichung umwandelt, wenn der Vergleich zwischen zwei eingeschlossenen Endpunkten durchgeführt wird.
quelle
Kurze Antwort mit momentjs :
Die Antwort basiert auf den obigen Antworten, ist jedoch verkürzt.
quelle
Wenn Sie einen Datumsbereich verwenden, der noch nicht beendet wurde (noch läuft), z. B. nicht endDate = '0000-00-00' setzen, können Sie ZWISCHEN nicht verwenden, da 0000-00-00 kein gültiges Datum ist!
Ich habe diese Lösung verwendet:
Wenn startdate2 höher als enddate ist, gibt es keine Überlappung!
quelle
Die Antwort ist zu einfach für mich, daher habe ich eine allgemeinere dynamische SQL-Anweisung erstellt, die prüft, ob eine Person überlappende Daten hat.
quelle
Die mathematische Lösung von @Bretana ist gut, vernachlässigt jedoch zwei spezifische Details:
Über den geschlossenen oder offenen Zustand von Intervallgrenzen gilt die Lösung von @Bretana für geschlossene Intervalle
kann für halboffene Intervalle umgeschrieben werden in:
Diese Korrektur ist notwendig, da eine offene Intervallgrenze per Definition nicht zum Wertebereich eines Intervalls gehört.
Und über leere Intervalle , nun, 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 anhand meiner Java- Zeitbibliothek Time4J anhand dieses Beispiels:
Die führende eckige Klammer "[" zeigt einen geschlossenen Start an, während die letzte Klammer ")" ein offenes Ende anzeigt.
Wie oben gezeigt, verletzen leere Intervalle die obige Überlappungsbedingung (insbesondere startA <endB), daher muss Time4J (und auch andere Bibliotheken) dies als speziellen Randfall behandeln, 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 halb geöffnet sein können, wie leere Datumsintervalle) auf ähnliche Weise behandelt.
quelle
Hier ist eine generische Methode, die lokal nützlich sein kann.
quelle
quelle
Mit Java util.Date, hier was ich getan habe.
quelle
Der einfachste Weg, dies zu tun, wäre meiner Meinung nach zu vergleichen, ob EndDate1 vor StartDate2 und EndDate2 vor StartDate1 liegt.
Dies gilt natürlich, wenn Sie Intervalle in Betracht ziehen, in denen StartDate immer vor EndDate liegt.
quelle
Ich hatte eine Situation, in der wir Daten anstelle von Daten hatten und die Daten sich nur am Anfang / Ende überschneiden konnten. Beispiel unten:
(Grün ist das aktuelle Intervall, blaue Blöcke sind gültige Intervalle, rote sind überlappende Intervalle).
Ich habe die Antwort von Ian Nelson an die folgende Lösung angepasst:
Dies entspricht allen Überlappungsfällen, ignoriert jedoch die zulässigen Überlappungsfälle.
quelle
Teilen Sie das Problem in Fälle auf und behandeln Sie dann jeden Fall .
Die Situation, dass sich zwei Datumsbereiche überschneiden, wird in zwei Fällen behandelt: Der erste Datumsbereich beginnt innerhalb des zweiten oder der zweite Datumsbereich beginnt innerhalb des ersten.
quelle
Sie können dies versuchen:
quelle
Dies war meine Lösung. Sie gibt true zurück, wenn sich die Werte nicht überschneiden:
X START 1 Y END 1
A START 2 B ENDE 2
quelle
Für Ruby habe ich auch folgendes gefunden:
Fand es hier mit netter Erklärung -> http://makandracards.com/makandra/984-test-if-two-date-ranges-overlap-in-ruby-or-rails
quelle
Die folgende Abfrage gibt mir die IDs an, für die sich der angegebene Datumsbereich (Start- und Enddatum) mit einem der Daten (Start- und Enddatum) in meinem Tabellennamen überschneidet
quelle