datetime - ändern - file rename creation date




Ermitteln, ob zwei Datumsbereiche überlappen (20)

Bei zwei Datumsbereichen ist es am einfachsten oder am effizientesten festzustellen, ob sich die beiden Datumsbereiche überschneiden.

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


das einfachste

Der einfachste Weg ist die Verwendung einer ausgereiften dedizierten Bibliothek für die Arbeit mit Datum und Uhrzeit.

someInterval.overlaps( anotherInterval )

java.time & ThreeTen-Extra

Das beste in der java.time ist das java.time Framework, das in Java 8 und höher integriert ist. 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 brauchen.

Was den language-agnostic Tag in dieser Frage betrifft, so steht der Quellcode für beide Projekte in anderen Sprachen zur Verfügung (beachten Sie deren Lizenzen).

Interval

Die Interval Klasse ist praktisch, erfordert jedoch Datums- und java.time.Instant ( java.time.Instant Objekte) anstelle von Nur-Datum-Werten. Wir fahren fort, indem wir den ersten Moment des Tages in UTC verwenden, um das Datum darzustellen.

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

Erstellen Sie ein Interval , um diese Zeitspanne darzustellen.

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

Wir können auch ein Interval mit einem Startmoment und einer Duration .

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

Der Vergleich mit Überlappungen ist einfach.

Boolean overlaps = interval_A.overlaps( interval_B );

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

Alle diese verwenden den Half-Open Ansatz, um eine Zeitspanne zu definieren, in der der Anfang inklusive ist und das Ende exklusiv ist .


Alle Lösungen, die eine Vielzahl von Bedingungen überprüfen, basierend auf den Bereichen, in denen die Bereiche zueinander stehen, 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 zur gleichen Zeit) beginnt, indem Sie die Bereiche gegebenenfalls im Voraus austauschen.

Dann können Sie eine Überlappung erkennen, wenn der andere Bereichsbeginn kleiner oder gleich dem ersten Bereichsende ist (wenn die Bereiche inklusive sind und Start- und Endzeiten enthalten) oder kleiner als (wenn die Bereiche Start und Ende einschließen) .

Unter Annahme von inklusiv an beiden Enden gibt es nur vier Möglichkeiten, von denen eine eine Nicht-Überlappung ist:

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

Der Endpunkt des Bereichs 2 tritt nicht ein. Also, in 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 mehr 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 in der zweiten if Anweisung einfach > durch >= ersetzen (für das erste Codesegment: im zweiten Codesegment würden Sie < statt <= ):

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

Sie begrenzen die Anzahl der Prüfungen, die Sie vornehmen müssen, erheblich, da Sie die Hälfte des Problembereichs frühzeitig entfernen, indem Sie sicherstellen, dass Bereich 1 nach Bereich 2 nicht startet.


Der einfachste Weg, dies zu tun, wäre meiner Meinung nach zu vergleichen, ob entweder EndDate1 vor StartDate2 und EndDate2 vor StartDate1 ist.

Das ist natürlich bei Intervallen, bei denen StartDate immer vor EndDate liegt.


Die hier gepostete Lösung funktionierte nicht für alle überlappenden Bereiche ...

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

Meine Arbeitslösung war:

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

Dies ist eine Erweiterung der ausgezeichneten 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 wenn: (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 wenn: (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 : 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 Intervalle zu überlappen

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

Wobei 🞐 eine strenge Ungleichheit in eine nicht-strikte Ungleichung umwandelt, wenn der Vergleich zwischen zwei eingeschlossenen Endpunkten durchgeführt wird.


Dieser Artikel Time Period Library for .NET beschreibt die Beziehung zweier Zeiträume durch die Enumeration PeriodRelation :

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


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

Hier ist meine Lösung in Java , die auch in unbegrenzten Intervallen 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));
}

Ich glaube, es genügt zu sagen, dass die beiden Bereiche überlappen, wenn:

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

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

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

Ich habe Ian Nelsons Antwort auf die folgende Lösung angepasst:

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

Dies entspricht allen Überlappungsfällen, ignoriert jedoch die erlaubten Überlappungsfälle.



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

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

Wenn Sie über zeitliche Beziehungen (oder irgendwelche anderen Intervallrelationen) nachdenken wollen, denken Sie an Allens Intervallalgebra . 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 unter URL verfügbar) sowie in Datum, Darwen und Lorentzos Zeitdaten und dem relationalen Modell (2002) oder Zeit- und Relationaltheorie: Zeitdatenbanken in das relationale Modell und SQL (2014; effektiv die zweite Ausgabe von TD & RM).

Die kurze (ish) Antwort ist: gegeben zwei .start A und B mit Komponenten .start und .start und 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 < optimieren, um Ihre Anforderungen für den Überlappungsgrad zu erfüllen.

ErikE kommentiert:

Sie können nur 13 bekommen, wenn Sie die Dinge lustig zählen ... Ich kann "15 mögliche Beziehungen, die zwei Intervalle haben können" bekommen, wenn ich damit verrückt werde. Durch vernünftiges Zählen bekomme ich nur sechs, und wenn Sie sich kümmern, ob A oder B zuerst kommt, bekomme ich nur drei (kein Schnittpunkt, teilweise Schnittpunkt, einer ganz im anderen). 15 geht so: [vorher: vor, anfang, innerhalb, ende, nachher], [anfang: anfang, innerhalb, ende, nachher], [innerhalb: innerhalb, ende, nachher], [ende: ende, nachher], [ nach: nach].

Ich denke, dass man die zwei Einträge "vorher: vorher" und "danach: nachher" nicht zählen kann. Ich könnte 7 Einträge sehen, wenn Sie einige Relationen mit ihren Inversen gleichsetzen (siehe das Diagramm in der referenzierten Wikipedia-URL; es hat 7 Einträge, von denen 6 eine unterschiedliche Inverse haben, wobei equals keine eindeutige Inverse 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-------|----------------------

Hier ist der Code, der die Magie macht:

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

Woher..

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

Beweis? Schau dir diesen Test- Konsolen-Code an .


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

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

Lassen Sie ConditionB bedeuten, dass DateRange A vollständig vor DateRange B steht
|---- DateRange A -----| _ _ |---Date Range B ----|
(True wenn EndA < StartB )

Dann besteht Überlappung, wenn weder A noch B wahr ist -
(Wenn eine Reihe nicht vollständig nach der anderen ist,
noch ganz vor dem anderen, dann müssen sie sich überschneiden.)

Jetzt sagt 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 die Kanten genau überlappen. Wenn Sie das ausschließen möchten,
Ändern Sie die Operatoren >= in > und <= in <

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

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

NOTIZ 3. Dank @tomosius liest 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 zu überprüfen, ob sich die Startdaten an oder vor den Enddaten befinden. Ableiten von oben:

Wenn Anfangs- und Enddatum nicht in Ordnung sein können, dh wenn es möglich ist, dass startA > endA oder startB > endB , dann müssen Sie auch überprüfen, ob sie in Ordnung sind. Das 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 Min() und Max() zu implementieren, müssen Sie (unter Verwendung von C-ternär für Kürze):
(StartA > StartB? Start A: StartB) <= (EndA < EndB? EndA: EndB)


Die Antwort ist zu einfach für mich, deshalb habe ich eine allgemeinere dynamische SQL-Anweisung erstellt, die überprü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)

Die folgende Abfrage gibt mir die IDs, für die der angegebene Datumsbereich (Start- und Enddatum mit einem der Daten (Start- und Enddatum) in meinem Tabellenname überlappt

select id from table_name where (START_DT_TM >= 'END_DATE_TIME'  OR   
(END_DT_TM BETWEEN 'START_DATE_TIME' AND 'END_DATE_TIME'))

This was my solution, it returns true when the values don't overlap:

X START 1 Y END 1

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

if (StartDate1 > StartDate2) swap(StartDate, EndDate);

(StartDate1 <= EndDate2) and (StartDate2 <= EndDate1);




language-agnostic