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

4voto

Ignacio Pascual Punkte 1865

Dies war meine JavaScript-Lösung mit moment.js:

// Aktuelle Reihendaten
var dateStart = moment("2014-08-01", "YYYY-MM-DD");
var dateEnd = moment("2014-08-30", "YYYY-MM-DD");

// Überprüfung mit den obigen Daten
var rangeUsedStart = moment("2014-08-02", "YYYY-MM-DD");
var rangeUsedEnd = moment("2014-08-015", "YYYY-MM-DD");

// Deckt der Bereich andere ab?
if((dateStart <= rangeUsedStart) && (rangeUsedEnd <= dateEnd)) {
    return false;
}
// Der Bereich überschneidet sich mit dem Start?
if((dateStart <= rangeUsedStart) && (rangeUsedStart <= dateEnd)) {
    return false;
}
// Der Bereich überschneidet sich mit dem Ende?
if((dateStart <= rangeUsedEnd) && (rangeUsedEnd <= dateEnd)) {
    return false;
}

// Alles gut
return true;

3voto

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) -- berücksichtigt innere und äußere Enddaten
        OR
        (@endDate1 BETWEEN @startDate2 AND @endDate2) -- berücksichtigt innere und äußere Startdaten
        OR
        (@startDate2 BETWEEN @startDate1 AND @endDate1) -- nur für äußeren Bereich erforderlich, in dem die Daten enthalten sind.
        ) THEN 1 ELSE 0 END
    )
    RETURN @Overlap

END
GO

-- Ausführung des obigen Codes
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

3voto

Meno Hochschild Punkte 40402

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

  1. Aspekt geschlossener oder halboffener Intervalle
  2. leere Intervalle

Zur Frage, ob Intervallgrenzen geschlossen oder offen sind, ist die Lösung von @Bretana gültig für geschlossene Intervalle

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

kann für halboffene Intervalle umgeschrieben werden zu:

(StartA < EndB) und (EndA > StartB)

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


Und zu leeren Intervallen, nun, hier gilt die oben gezeigte Beziehung NICHT. Leere Intervalle, die per Definition keinen gültigen Wert enthalten, müssen als spezieller Fall behandelt werden. Ich zeige dies anhand meiner Java-Zeitbibliothek Time4J anhand dieses Beispiels:

MomentInterval a = MomentInterval.between(Instant.now(), Instant.now().plusSeconds(2));
MomentInterval b = a.collapse(); // mache b aus a ein leeres Intervall

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 führende eckige Klammer "[" zeigt einen geschlossenen Start an, während die letzte Klammer ")" ein offenes Ende anzeigt.

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 überschneidet b: " + a.intersects(b)); // a überschneidet b: false

Wie oben gezeigt, verletzen leere Intervalle die Überschneidungsbedingung oben (insbesondere startA < endB), daher muss Time4J (und auch andere Bibliotheken) dies als speziellen Grenzfall behandeln, um sicherzustellen, dass die Überlappung eines beliebigen Intervalls mit einem leeren Intervall nicht existiert. Natürlich werden Datumintervalle (die standardmäßig in Time4J geschlossen sind, aber auch halboffen sein können, wie leere Datumintervalle) ähnlich behandelt.

3voto

Gus Punkte 14539

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

Bildbeschreibung hier eingeben

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

Ich habe die Antwort von Ian Nelson zu folgender Lösung angepasst:

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

Dies trifft alle Überlappungsfälle, ignoriert aber die erlaubten Überlappungsfälle.

3voto

Basil Bourque Punkte 256611

das einfachste

Der einfachste Weg ist es, eine gut konzipierte dedizierte Bibliothek für Datum-Zeit-Arbeiten zu verwenden.

someInterval.overlaps( anotherInterval )

java.time & ThreeTen-Extra

Das Beste in der Branche ist das java.time-Framework, das in Java 8 und später eingebaut ist. Dazu kommt das ThreeTen-Extra-Projekt, das java.time mit zusätzlichen Klassen ergänzt, insbesondere mit der hier benötigten Interval-Klasse.

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

Interval

Die org.threeten.extra.Interval-Klasse ist praktisch, erfordert jedoch Datum-Zeit-Momente (java.time.Instant-Objekte) anstelle von nur Datumswerten. Daher gehen wir vor, indem wir den ersten Moment des Tages in UTC zur Darstellung des Datums verwenden.

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

Erstellen Sie ein Interval, um diesen Zeitraum darzustellen.

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

Sie können auch ein Interval mit einem Startmoment plus einer Duration definieren.

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

Der Vergleich zur Überlappung ist einfach.

Boolean overlaps = interval_A.overlaps( interval_B );

Sie können ein Interval gegen ein anderes Interval oder Instant vergleichen:

All diese verwenden den Ansatz des Halboffenen zum Definieren eines Zeitraums, bei dem der Anfang inklusiv und das Ende exklusiv ist.

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