2つの日付範囲が与えられた場合、2つの日付範囲が重複しているかどうかを判断する最も簡単または最も効率的な方法は何ですか?
例として、DateTime変数StartDate1
to EndDate1
および StartDate2
toで示される範囲があるとしEndDate2
ます。
2つの日付範囲が与えられた場合、2つの日付範囲が重複しているかどうかを判断する最も簡単または最も効率的な方法は何ですか?
例として、DateTime変数StartDate1
to EndDate1
および StartDate2
toで示される範囲があるとしEndDate2
ます。
回答:
(StartA <= EndB)および(EndA> = StartB)
証明:
ConditionAは、DateRange Bの後にDateRange Aが完全に続くことを意味する
_ |---- DateRange A ------|
|---Date Range B -----| _
(trueの場合StartA > EndB
)
ConditionBは、DateRange Aが完全にDateRange Bの前であることを意味します
|---- DateRange A -----| _
_ |---Date Range B ----|
(True if EndA < StartB
)
次に、AもBも真でない場合、重複が存在します-
(1つの範囲が完全に他の後に
も完全に前にもない場合、それらは重複する必要があります。)
現在、ドモーガンの法則の 1つは次のように述べています。
Not (A Or B)
<=> Not A And Not B
これは次のように変換されます: (StartA <= EndB) and (EndA >= StartB)
注:これには、エッジが正確に重なる条件が含まれます。あなたはそれを除外したい場合は、
変更>=
に演算子を>
、と<=
します<
注2。@Baodadのおかげで、参照このブログを、実際のオーバーラップは、少なくともあります:
{ endA-startA
、endA - startB
、endB-startA
、endB - startB
}
(StartA <= EndB) and (EndA >= StartB)
(StartA <= EndB) and (StartB <= EndA)
注3。@tomosiusのおかげで、短いバージョンが読み取られます。
DateRangesOverlap = max(start1, start2) < min(end1, end2)
これは実際には、より長い実装の構文上のショートカットです。これには、開始日がendDates以前であるかどうかを確認する追加のチェックが含まれます。上からこれを導きます:
開始日と終了日が順不同である可能性がある場合、つまりstartA > endA
orまたはである可能性がある場合はstartB > endB
、それらが正しいかどうかも確認する必要があります。つまり、次の2つの有効性ルールを追加する必要があります:
(StartA <= EndB) and (StartB <= EndA) and (StartA <= EndA) and (StartB <= EndB)
or:
(StartA <= EndB) and (StartA <= EndA) and (StartB <= EndA) and (StartB <= EndB)
or
(StartA <= Min(EndA, EndB) and (StartB <= Min(EndA, EndB))
またはor:
(Max(StartA, StartB) <= Min(EndA, EndB)
しかし、Min()
and を実装Max()
するには、(簡潔にするためにCの3項を使用して)次のようにコーディングする必要があります。
(StartA > StartB? Start A: StartB) <= (EndA < EndB? EndA: EndB)
Start
とEnd
意味です。TopとBottom、またはEastとWest、またはHighValueとLoValueという名前の2つの変数がある場合、どこかで、値のペアの1つが反対の変数に格納されていないことを確認する必要があります。-2つのペアのうちの1つだけです。これは、値の両方のペアを切り替えた場合にも機能するためです。
start
を追加することができますend
(「null start」=「時間の始まりから」および「null end」=「時間の終わりまで」という(startA === null || endB === null || startA <= endB) && (endA === null || startB === null || endA >= startB)
DateRangesOverlap = max(start1, start2) < min(end1, end2)
次の場合、2つの範囲が重複していると言えば十分だと思います。
(StartDate1 <= EndDate2) and (StartDate2 <= EndDate1)
(StartDate1 <= EndDate2) and (EndDate1 >= StartDate2)
表記の方がわかりやすいと思います。テストではRange1が常に左側にあります。
<=
し<
ます。
この記事.NET用の期間ライブラリでは、列挙型PeriodRelationによる2つの期間の関係について説明しています。
// ------------------------------------------------------------------------
public enum PeriodRelation
{
After,
StartTouching,
StartInside,
InsideStartTouching,
EnclosingStartTouching,
Enclosing,
EnclosingEndTouching,
ExactMatch,
Inside,
InsideEndTouching,
EndInside,
EndTouching,
Before,
} // enum PeriodRelation
時間的関係(またはその他の区間関係については、ここまで来てください)についての推論については、アレンの区間代数を検討してください。これは、2つの間隔が互いに対して持つことができる13の可能な関係を示しています。他の参考文献を見つけることができます—「Allen Interval」は有効な検索用語のようです。これらの操作に関する情報は、SnodgrassのSQLでの時間指向アプリケーションの開発(PDFはURLでオンラインで利用可能)、Date、DarwenおよびLorentzosの時間データと関係モデル(2002)または 時間と関係理論:時間データベースRelational Model and SQL(2014;事実上、TD&RMの第2版)。
short(ish)の答えは次のとおりです。2つの日付間隔がA
ありB
、コンポーネント.start
と.end
制約.start <= .end
が指定されている場合、2つの間隔は次の場合に重複します。
A.end >= B.start AND A.start <= B.end
>=
vs >
と<=
vsの使用を調整して<
、重複の程度に関する要件を満たすことができます。
ErikEのコメント:
面白いことを数えると13しか得られません...私がそれに夢中になったとき、私は「2つの間隔が持つことができる15の可能な関係」を得ることができます。賢明なカウントでは、6しか得られません。AとBのどちらが先かを気にかけても、3しか得られません(交差せず、部分的に交差し、1つは完全に他の中にあります)。15は次のようになります:[before:before、start、within、end、after]、[start:start、within、end、after]、[within:within、end、after]、[end:end、after]、[後:後]。
「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-------|----------------------
オーバーラップ自体も計算する必要がある場合は、次の式を使用できます。
overlap = max(0, min(EndDate1, EndDate2) - max(StartDate1, StartDate2))
if (overlap > 0) {
...
}
範囲が相互に関連している場所に基づいて多数の条件をチェックするすべてのソリューションは、特定の範囲がより早く始まるようにするだけで大幅に簡略化できます!必要に応じて範囲を前もって交換することにより、最初の範囲がより早く(または同時に)開始するようにします。
次に、他の範囲の開始が最初の範囲の終了以下(範囲が包括的で、開始時間と終了時間の両方を含む場合)またはより小さい(範囲に開始が含まれ、終了が含まれない場合)、オーバーラップを検出できます。 。
両端を含むと仮定すると、重複しない可能性は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
範囲が最後に開始し、排他的に含まれている場合、あなただけ交換する必要が>
で>=
第二中if
(:第2のコードセグメントでは、あなたが使用したい第1のコードセグメントのための文<
ではなく<=
):
|----------------------| range 1
|---> range 2 overlap
|---> range 2 overlap
|---> range 2 no overlap
|---> range 2 no overlap
範囲1が範囲2の後に開始されないようにすることで問題のスペースの半分を早期に削除するため、実行する必要があるチェックの数を大幅に制限します。
JavaScriptを使用したさらに別のソリューションを次に示します。私のソリューションの専門:
テストは整数に基づいていますが、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秒)
私はするだろう
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);
}
これが魔法をかけるコードです:
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));
どこ..
証明?このテストコンソールコードの要点を確認してください。
これが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));
}
!startA.after(endB)
startA <= endBを!endA.before(startB)
意味し、startB <= endAを意味します。これらは、オープンインターバルではなく、クローズドインターバルの基準です。
endB == null
およびstartA == null
オープンインターバルのチェック。
endB == null
、startA == null
、endA == null
およびstartB == null
無制限区間ではなく開区間をチェックするためのすべての基準です。無制限の間隔と開いた間隔の違いの例:(10、20)と(20、null)は、重なり合わない2つの開いた間隔です。最後のものは無限の終わりを持っています。関数はtrueを返しますが、間隔には20が含まれないため、間隔はオーバーラップしません。(単純化するために、タイムスタンプの代わりに使用された数値)
ここに投稿されたソリューションは、すべての重複範囲に対して機能しませんでした...
---------------------- | ------- A ------- | ----------- ----------- | ---- B1 ---- | | ---- B2 ---- | | ---- B3 ---- | | ---------- B4 ---------- | | ---------------- B5 ---------------- | | ---- B6 ---- | ---------------------- | ------- A ------- | ----------- ----------- | ------ B7 ------- | | ---------- B8 ----------- | | ---- B9 ---- | | ---- B10 ----- | | -------- B11 -------- | | ---- B12 ---- | | ---- B13 ---- | ---------------------- | ------- A ------- | ----------- -----------
私の作業解決策は:
AND( ( 'start_date' BETWEEN STARTDATE AND ENDDATE)-内部日付と終了日付外部に対応 または ( 'end_date' BETWEEN STARTDATE AND ENDDATE)-内部および開始日の外部に対応 または (STARTDATE BETWEEN 'start_date' AND 'end_date')-日付が内側にある外側の範囲に必要なのは1つだけです。 )
これは、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;
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
もっとも単純な
最も簡単な方法は、日付時刻の作業に適切に設計された専用ライブラリを使用することです。
someInterval.overlaps( anotherInterval )
ビジネスで最も優れているのは、java.time
Java 8以降に組み込まれているフレームワークです。これに、java.timeを追加のクラス、特にここで必要なクラスで補足するThreeTen-Extraプロジェクトを追加しInterval
ます。
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
、開始が包括的で終了が排他的である期間を定義するアプローチを使用します。
これは、@ 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 ----]
オーバーラップ差分: (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 ----)
オーバーラップ差分: (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:右開、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)
等...
最後に、2つの間隔が重なる一般的な条件は次のとおりです。
(StartA <🞐EndB)および(EndA>🞐StartB)
ここで、🞐は、含まれる2つのエンドポイント間で比較が行われるたびに、厳密な不等式を非厳密な不等式に変換します。
まだ終了していない(まだ進行中の)日付範囲を使用している場合(例:endDate = '0000-00-00'を設定しない場合)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は重複しません。
答えは単純すぎるので、日付が重複していないかどうかを確認する、より一般的な動的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)
@Bretanaによって与えられる数学的解は良いですが、2つの特定の詳細を無視します:
区間境界の閉じた状態または開いた状態について、閉じた区間に有効な@Bretanaの解
(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(および他のライブラリも)は、任意の間隔と空の間隔のオーバーラップを保証するために、特別なエッジケースとして処理する必要があります。存在しません。もちろん、日付間隔(Time4Jではデフォルトで閉じられていますが、空の日付間隔のようにハーフオープンにすることもできます)も同様の方法で処理されます。
ローカルで役立つ一般的な方法を次に示します。
// 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
*/
}
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");
}
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;
}
あなたはこれを試すことができます:
//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);
これは私の解決策でした、値が重複しない場合はtrueを返します。
X開始1 Y終了1
Aスタート2 Bエンド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
ルビーの場合もこれを見つけました:
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
以下のクエリは、指定された日付範囲(開始日と終了日)が私の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'))