web-dev-qa-db-ja.com

2つの日付範囲が重なるかどうかを確認

2つの日付範囲がある場合、2つの日付範囲が重複しているかどうかを判断するための最も簡単な方法または最も効率的な方法は何ですか?

例として、DateTime変数のStartDate1からEndDate1 および StartDate2からEndDate2で表される範囲があるとします。

1096
Ian Nelson

(StartA <= EndB)および(EndA> = StartB)

証明:
条件AでDateRange AがDateRange Bの後に完全に一致することを意味する
_ |---- DateRange A ------| |---Date Range B -----| _
StartA > EndBの場合は真)

条件BでDateRange AがDateRange Bよりも完全に前であることを意味する
|---- DateRange A -----| _ _ |---Date Range B ----|
EndA < StartBの場合は真)

AとBのどちらも真実でない場合は、重複が存在します -
(一方の範囲がもう一方の範囲を完全に超えていない場合は、
または完全に他のものよりも前では、それらは重なっていなければなりません。

De Morganの法律の1つ は次のように述べています。

Not (A Or B) <=> Not A And Not B

これは次のように解釈されます。(StartA <= EndB) and (EndA >= StartB)


注:これには、端が正確に重なる条件が含まれます。それを除外したいのなら、
>=演算子を>に、<=<に変更


注2。 @Baodadのおかげで、 このブログ を見てください、実際のオーバーラップは少なくとものものです:
{endA-startAendA - startBendB-startAendB - startB}

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


注3。 @tomosiusのおかげで、より短いバージョンでは、
DateRangesOverlap = max(start1, start2) < min(end1, end2)
これは実際には長い実装の構文上のショートカットで、開始日が終了日より前か終了日であることを確認するための追加チェックが含まれています。上記からこれを派生させる:

開始日と終了日がずれている可能性がある場合、つまりstartA > endAまたはstartB > endBが可能である場合は、それらが正しいことを確認する必要もあります。そのため、さらに2つの有効性規則を追加する必要があります。
(StartA <= EndB) and (StartB <= EndA) and (StartA <= EndA) and (StartB <= EndB)または:
(StartA <= EndB) and (StartA <= EndA) and (StartB <= EndA) and (StartB <= EndB)または
(StartA <= Min(EndA, EndB) and (StartB <= Min(EndA, EndB))または:
(Max(StartA, StartB) <= Min(EndA, EndB)

しかしMin()Max()を実装するには、コードを書く必要があります(簡潔さのためにCの三項を使います)、
(StartA > StartB? Start A: StartB) <= (EndA < EndB? EndA: EndB)

2062
Charles Bretana

以下の場合、2つの範囲が重なると言うことで十分であると思います。

(StartDate1 <= EndDate2) and (StartDate2 <= EndDate1)
358
Ian Nelson

この記事 .NET用期間ライブラリ 2つの期間の関係を列挙PeriodRelationで説明します。

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

enter image description here

98
user687474

時間的関係(または他の任意の区間関係、そのことになること)を推論するために、 Allenの区間代数 を検討してください。それは2つの間隔が互いに関して持つことができる13の可能な関係について説明します。あなたは他の参考文献を見つけることができます - 「アレン間隔」は有効な検索語のようです。これらの操作に関する情報は、Snodgrassの SQLでの時間指向アプリケーションの開発 (オンラインのPDF URL)、およびDate、Darwen、Lorentzos 時間データとリレーショナルモデル (2002)にもあります。 時間と関係理論:関係モデルとSQLにおける時間データベース (2014;事実上TD&RMの第2版)。


短い(ish)答えは、コンポーネント.startおよび.endおよび制約条件.start <= .endを含む2つの日付間隔AおよびBが与えられた場合、2つの間隔は重なります。

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

>= vs >および<= vs <の使用を調整して、重複の程度に関する要件を満たすことができます。


ErikEのコメント:

あなたが物事をおかしいと数えるならば、あなたは13を得ることができるだけです...私がそれに夢中になるとき、私は「2つの間隔が持つことができる15の可能な関係」を得ることができます。賢明な計算では、私は6つしか得られません、そして、あなたがAまたはBが最初に来るかどうか気にすることを捨てるならば、私は3つだけを得ます(交差しない、部分的に交差します。 [前:前、開始、範囲内、終了、後]、[開始:開始、範囲内、終了、後]、[範囲内:範囲内、終了、後]、[終了:終了、後]、[後:後]。

'before:before'と 'after:after'の2つのエントリは数えられないと思います。いくつかの関係をその逆と同じにすると、7つのエントリを見ることができます(参照されているWikipediaのURLの図を参照してください。7つのエントリがあり、そのうち6つは異なる逆行列を持ちます。そして、3つが賢明かどうかはあなたの要求次第です。

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

重なり自体も計算する必要がある場合は、次の式を使用できます。

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

範囲が互いに関連している場所に基づいて多数の条件をチェックするすべての解決策は、特定の範囲がより早く開始されることを確認する!によって大幅に簡略化できます。同時に)必要なら前もって範囲を交換することによって。

次に、他の範囲の開始が最初の範囲の終了(範囲を含む場合は開始時間と終了時間の両方を含む)以下、または未満(範囲が開始を含み、終了を除く場合)以下の場合、オーバーラップを検出できます。 。

両端を含むと仮定すると、4つの可能性しかありません。

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

範囲2の終点は入りません。だから、疑似コードでは:

def doesOverlap (r1, r2):
    if r1.s > r2.s:
        swap r1, r2
    if r2.s > r1.e:
        return false
    return true

これはさらに単純化されます。

def doesOverlap (r1, r2):
    if r1.s > r2.s:
        swap r1, r2
    return r2.s <= r1.e

範囲が最初と最後で含まれる場合は、2番目のifステートメントで>>=に置き換えるだけです(最初のコードセグメントの場合、2番目のコードセグメントでは、<ではなく<=を使用します)。

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

範囲1が範囲2の後に始まらないようにすることで、問題スペースの半分を早期に削除するため、チェックの数を大幅に制限できます。

16
paxdiablo

これがJavaScriptを使ったもう一つの解決策です。私の解決策の特色:

  • Null値を無限大として扱います
  • 下限は包括的で上限は排他的であると仮定します。
  • たくさんのテストが付属しています

テストは整数に基づいていますが、JavaScriptの日付オブジェクトは比較可能なので、2つの日付オブジェクトを入れることもできます。あるいは、ミリ秒のタイムスタンプを入れることもできます。

コード:

/**
 * Compares to comparable objects to find out whether they overlap.
 * It is assumed that the interval is in the format [from,to) (read: from is inclusive, to is exclusive).
 * A null value is interpreted as infinity
 */
function intervalsOverlap(from1, to1, from2, to2) {
    return (to2 === null || from1 < to2) && (to1 === null || to1 > from2);
}

テスト:

describe('', function() {
    function generateTest(firstRange, secondRange, expected) {
        it(JSON.stringify(firstRange) + ' and ' + JSON.stringify(secondRange), function() {
            expect(intervalsOverlap(firstRange[0], firstRange[1], secondRange[0], secondRange[1])).toBe(expected);
        });
    }

    describe('no overlap (touching ends)', function() {
        generateTest([10,20], [20,30], false);
        generateTest([20,30], [10,20], false);

        generateTest([10,20], [20,null], false);
        generateTest([20,null], [10,20], false);

        generateTest([null,20], [20,30], false);
        generateTest([20,30], [null,20], false);
    });

    describe('do overlap (one end overlaps)', function() {
        generateTest([10,20], [19,30], true);
        generateTest([19,30], [10,20], true);

        generateTest([10,20], [null,30], true);
        generateTest([10,20], [19,null], true);
        generateTest([null,30], [10,20], true);
        generateTest([19,null], [10,20], true);
    });

    describe('do overlap (one range included in other range)', function() {
        generateTest([10,40], [20,30], true);
        generateTest([20,30], [10,40], true);

        generateTest([10,40], [null,null], true);
        generateTest([null,null], [10,40], true);
    });

    describe('do overlap (both ranges equal)', function() {
        generateTest([10,20], [10,20], true);

        generateTest([null,20], [null,20], true);
        generateTest([10,null], [10,null], true);
        generateTest([null,null], [null,null], true);
    });
});

Karma&jasmine&PhantomJSで実行した結果:

PhantomJS 1.9.8(Linux):20の20の成功の実行(0.003秒/ 0.004秒)

13
yankee

これは言語にとらわれないものとしてタグ付けされていることを私は知っていますが、Javaで実装している皆さんのために:ホイールを再発明してJoda Timeを使用しないでください。

http://joda-time.sourceforge.net/api-release/org/joda/time/base/AbstractInterval.html#overlaps(org.joda.time.ReadableInterval

9
Stefan Haberl

私はやります

StartDate1.IsBetween(StartDate2, EndDate2) || EndDate1.IsBetween(StartDate2, EndDate2)

IsBetweenは次のようなものです。

    public static bool IsBetween(this DateTime value, DateTime left, DateTime right) {
        return (value > left && value < right) || (value < left && value > right);
    }
8
Bob

これは Java での私の解決策です。

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));
}
7
Khaled.K

enter image description here

これが魔法のようなコードです。

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

どこで..

  • A - > 1スタート
  • B - > 1終わり
  • C - > 2スタート
  • D - > 2終わり

証明?このテストをチェックしてください コンソールコードGist

7

ここに掲載されている解決策は、すべての重なっている範囲に対してうまくいきませんでした...

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

私の実用的な解決策は以下のとおりです。

 AND(
( 'START_DATE' BETWEEN STARTDATE AND ENDDATE) - 内側および終了日外側
 OR 
( 'end_date' BETWEEN STARTDATE AND ENDDATE)に対応します。 - 内側および開始日の外側
または
(STARTDATE BETWEEN 'start_date'と 'end_date')を考慮 - 日付が内側の外側の範囲に必要なものは1つだけ。
 
6
on_

これはmoment.jsを使った私のJavaScriptソリューションです:

// Current row dates
var dateStart = moment("2014-08-01", "YYYY-MM-DD");
var dateEnd = moment("2014-08-30", "YYYY-MM-DD");

// Check with dates above
var rangeUsedStart = moment("2014-08-02", "YYYY-MM-DD");
var rangeUsedEnd = moment("2014-08-015", "YYYY-MM-DD");

// Range covers other ?
if((dateStart <= rangeUsedStart) && (rangeUsedEnd <= dateEnd)) {
    return false;
}
// Range intersects with other start ?
if((dateStart <= rangeUsedStart) && (rangeUsedStart <= dateEnd)) {
    return false;
}
// Range intersects with other end ?
if((dateStart <= rangeUsedEnd) && (rangeUsedEnd <= dateEnd)) {
    return false;
}

// All good
return true;
5
Ignacio Pascual

最も簡単な

最も簡単な方法は、日時作業用によく設計された専用ライブラリを使用することです。

someInterval.overlaps( anotherInterval )

Java.timeとThreeTen-Extra

ビジネスで最高のものは、Java 8以降に組み込まれた Java.time フレームワークです。それに、Java.timeに追加のクラス、具体的にはここで必要な Interval クラスを追加する ThreeTen-Extra プロジェクトを追加します。

この質問のlanguage-agnosticタグに関しては、両方のプロジェクトのためのソースコードは他の言語での使用のために利用可能です(彼らのライセンスを考慮してください)。

Interval

org.threeten.extra.Interval クラスは便利ですが、日付のみの値ではなく、日付時刻(Java.time.Instantオブジェクト)が必要です。そのため、UTCでその日の最初の瞬間を使用して日付を表します。

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

その期間を表すIntervalを作成します。

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

開始時刻と Interval を付けてDurationを定義することもできます。

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

オーバーラップのテストと比較するのは簡単です。

Boolean overlaps = interval_A.overlaps( interval_B );

Interval を別の Interval または Instant と比較できます。

これらはすべてHalf-Openアプローチを使用して、開始が 包括的 で終了が exclusive である期間を定義します。

3
Basil Bourque

答えは私には簡単すぎるので、私は人が重複する日付を持っているかどうかを確認するより一般的な動的SQLステートメントを作成しました。

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)
2
Tom McDonough

まだ終わっていない(まだ進行中の)日付範囲を使用している場合0000-00-00は有効な日付ではないため、endDate = '0000-00-00'に設定しないとBETWEENを使用できません。

私はこの解決策を使いました。

(Startdate BETWEEN '".$startdate2."' AND '".$enddate2."')  //overlap: starts between start2/end2
OR (Startdate < '".$startdate2."' 
  AND (enddate = '0000-00-00' OR enddate >= '".$startdate2."')
) //overlap: starts before start2 and enddate not set 0000-00-00 (still on going) or if enddate is set but higher then startdate2

Startdate2がenddateよりも高い場合、重複はありません。

2
jack

これは 優秀な答え @ charles-bretanaによる/への拡張です。

ただし、答えは、オープン、クローズ、およびハーフオープン(またはハーフクローズ)インターバルを区別しません。

ケース1 :A、Bは閉区間

A = [StartA, EndA]
B = [StartB, EndB]

                         [---- DateRange A ------]   (True if StartA > EndB)
[--- Date Range B -----]                           


[---- DateRange A -----]                             (True if EndA < StartB)
                         [--- Date Range B ----]

Iff:(StartA <= EndB) and (EndA >= StartB)と重なる

ケース2 :A、Bはオープン間隔

A = (StartA, EndA)
B = (StartB, EndB)

                         (---- DateRange A ------)   (True if StartA >= EndB)
(--- Date Range B -----)                           

(---- DateRange A -----)                             (True if EndA <= StartB)
                         (--- Date Range B ----)

Iff:(StartA < EndB) and (EndA > StartB)と重なる

ケース3 :A、Bは右開き

A = [StartA, EndA)
B = [StartB, EndB)

                         [---- DateRange A ------)   (True if StartA >= EndB) 
[--- Date Range B -----)                           

[---- DateRange A -----)                             (True if EndA <= StartB)
                         [--- Date Range B ----)

重複条件:(StartA < EndB) and (EndA > StartB)

ケース4 :A、Bは開いたまま

A = (StartA, EndA]
B = (StartB, EndB]

                         (---- DateRange A ------]   (True if StartA >= EndB)
(--- Date Range B -----]                           

(---- DateRange A -----]                             (True if EndA <= StartB)
                         (--- Date Range B ----]

重複条件:(StartA < EndB) and (EndA > StartB)

ケース5 :Aは右開き、Bは閉じた

A = [StartA, EndA)
B = [StartB, EndB]

                         [---- DateRange A ------)    (True if StartA > EndB)
[--- Date Range B -----]                           


[---- DateRange A -----)                              (True if EndA <= StartB)  
                         [--- Date Range B ----]

重複条件:(StartA <= EndB) and (EndA > StartB)

etc ...

最後に、2つの区間が重なる一般的な条件は、

(StartA <???? EndB)および(EndA> ???? StartB)

どこ? 2つの含まれる端点間で比較が行われるたびに、厳密な不等式を厳密でないものに変換します。

2
user2314737

Microsoft SQL Serverの場合 - SQL関数

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
1

私の考えでは、これを行う最も簡単な方法は、EndDate1がStartDate2より前で、EndDate2がStartDate1より前かを比較することです。

もちろん、StartDateが常にEndDateより前になる間隔を検討しているのであれば。

1
AlexDrenea

Java util.Dateを使って、ここで私がしたこと。

    public static boolean checkTimeOverlaps(Date startDate1, Date endDate1, Date startDate2, Date endDate2)
    {
        if (startDate1 == null || endDate1 == null || startDate2 == null || endDate2 == null)
           return false;

        if ((startDate1.getTime() <= endDate2.getTime()) && (startDate2.getTime() <= endDate1.getTime()))
           return true;

        return false;
    }
1
Shehan Simen

@Bretanaによって与えられる数学的な解決策は良いですが、2つの具体的な詳細を無視します。

  1. 閉または半開区間の側面
  2. 空の間隔

区間境界の閉じた状態または開いた状態については、@ Bretanaの解法valid 閉じた区間に対して

(StartA <= EndB)および(EndA> = StartB)

半開区間の場合は に書き換えることができます。

(StartA <EndB)と(EndA> StartB)

定義上、開いた区間境界は区間の値範囲に属していないため、この修正が必要です。


そして、 空の区間 について、まあ、ここで上に示した関係は成り立ちません。定義上有効な値を含まない空の区間は特別な場合として扱われなければなりません。この例では、私のJavaタイムライブラリ Time4J でそれを示しています。

MomentInterval a = MomentInterval.between(Instant.now(), Instant.now().plusSeconds(2));
MomentInterval b = a.collapse(); // make b an empty interval out of a

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)

先行角括弧「[」は閉じた開始を示し、最後の括弧「)」は開いた終了を示します。

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

上に示したように、空の区間は上記のオーバーラップ条件(特にstartA <endB)に違反しているので、Time4J(および他のライブラリも)は任意の区間と空の区間のオーバーラップを保証するために特別なEdgeケースとして扱う存在しない。もちろん、日付間隔(Time4Jではデフォルトで閉じられていますが、空の日付間隔のように半分開いていてもかまいません)も同様の方法で処理されます。

1
Meno Hochschild

ローカルで役立つ一般的なメソッドを次に示します。

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

私はdatetimeの代わりに日付があり、日付が開始/終了時にのみ重なる可能性があるという状況を経験しました。以下の例:

enter image description here

(緑が現在の間隔、青のブロックが有効な間隔、赤のブロックが重なっている間隔です)。

Ian Nelsonの答えを次の解決策に合わせました。

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

これはすべてのオーバーラップケースに一致しますが、許可されたオーバーラップケースを無視します。

1
Gus
public static class NumberExtensionMethods
    {
        public static Boolean IsBetween(this Int64 value, Int64 Min, Int64 Max)
        {
            if (value >= Min && value <= Max) return true;
            else return false;
        }

        public static Boolean IsBetween(this DateTime value, DateTime Min, DateTime Max)
        {
            Int64 numricValue = value.Ticks;
            Int64 numericStartDate = Min.Ticks;
            Int64 numericEndDate = Max.Ticks;

            if (numricValue.IsBetween(numericStartDate, numericEndDate) )
            {
                return true;
            }

            return false;
        }
    }

public static Boolean IsOverlap(DateTime startDate1, DateTime endDate1, DateTime startDate2, DateTime endDate2)
        {
            Int64 numericStartDate1 = startDate1.Ticks;
            Int64 numericEndDate1 = endDate1.Ticks;
            Int64 numericStartDate2 = startDate2.Ticks;
            Int64 numericEndDate2 = endDate2.Ticks;

            if (numericStartDate2.IsBetween(numericStartDate1, numericEndDate1) ||
                numericEndDate2.IsBetween(numericStartDate1, numericEndDate1) ||
                numericStartDate1.IsBetween(numericStartDate2, numericEndDate2) ||
                numericEndDate1.IsBetween(numericStartDate2, numericEndDate2))
            {
                return true;
            }

            return false;
        } 


if (IsOverlap(startdate1, enddate1, startdate2, enddate2))
            {
                Console.WriteLine("IsOverlap");
            }
1
mmarjeh

Rubyのために私もこれを見つけました:

class Interval < ActiveRecord::Base

  validates_presence_of :start_date, :end_date

  # Check if a given interval overlaps this interval    
  def overlaps?(other)
    (start_date - other.end_date) * (other.start_date - end_date) >= 0
  end

  # Return a scope for all interval overlapping the given interval, including the given interval itself
  named_scope :overlapping, lambda { |interval| {
    :conditions => ["id <> ? AND (DATEDIFF(start_date, ?) * DATEDIFF(?, end_date)) >= 0", interval.id, interval.end_date, interval.start_date]
  }}

end

ここでそれをいい説明で見つけた - > http://makandracards.com/makandra/984-test-if-two-date-ranges-overlap-in-Ruby-or-Rails

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

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

問題をケースに分割してからそれぞれのケースを処理する

「2つの日付範囲が交差する」という状況は、2つのケースでカバーされます。1番目の日付範囲は2番目の日付範囲から始まり、2番目の日付範囲は最初の日付範囲から始まります。

0
Colonel Panic

覚えやすい解決策は次のようになります。
min(ends)>max(starts)

0
Radacina

入力として日付範囲を指定し、それがデータベース内の既存の日付範囲と重複しているかどうかを調べたい場合は、以下の条件が正常にあなたの要求を満たすことができます。

フォーム入力から@StartDate@EndDateを指定したとします。

条件は次のとおりです。

@StartDateexistingStartDateの前でexistingEndDateの後ろにある場合、@StartDateは既存の日付範囲の中央にあると言えるので、重複すると結論付けることができます。

@StartDate >=existing.StartDate And @StartDate <= existing.EndDate) 

@StartDateexistingStartDateより遅れているが@EndDateexistingStartDateより進んでいる場合、それは重なると言えるでしょう。

 (@StartDate <= existing.StartDate And @EndDate >= existing.StartDate)

@StartDateexistingStartDateより遅れていて、そして@EndDateexistingEndDateより進んでいる場合、提供された日付範囲は既存の日付範囲を逸脱していると結論付けることができます。

 (@StartDate <= existing.StartDate And @EndDate >= existing.EndDate))

いずれかの条件が当てはまる場合、指定した日付範囲はデータベース内の既存の日付範囲と重複します。

0
AL-zami

以下のクエリは私に与えられた日付範囲(開始日と終了日)が私のtable_nameの日付(開始日と終了日)のいずれかと重なるIDを与えます

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

簡単な解決策:

compare the two dates: 
    A = the one with smaller start date, B = the one with bigger start date
if(A.end < B.start)
    return false
return true
0
sorry_I_wont

これを試すことができます:

//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);
0
Ilya

これは私の解決策でした。値が重ならない場合はtrueを返します。

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
0
Fez Vrasta

これが moment js を使ったもう一つの短い答えです。

function isOverlapping(startDate1, endDate1, startDate2, endDate2){ 
return moment(startDate1).isSameOrBefore(endDate2) && 
moment(startDate2).isSameOrBefore(endDate1);
}

答えは上記の答えに基づいていますが、短縮されています。

0
Nitin Jadhav