두 개의 기간이 주어지면 두 기간이 중복되는지 여부를 결정하는 가장 간단하거나 효율적인 방법은 무엇입니까?
예를 들어, DateTime 변수로 표시되는 범위 StartDate1
가 EndDate1
및 로 있다고 가정 StartDate2
합니다 EndDate2
.
두 개의 기간이 주어지면 두 기간이 중복되는지 여부를 결정하는 가장 간단하거나 효율적인 방법은 무엇입니까?
예를 들어, DateTime 변수로 표시되는 범위 StartDate1
가 EndDate1
및 로 있다고 가정 StartDate2
합니다 EndDate2
.
답변:
(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의 법률 중 하나는 다음과 같이 말합니다.
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)
이것은 실제로 더 긴 구현에 대한 구문 바로 가기입니다. 여기에는 시작 날짜가 종료 날짜 또는 그 이전인지 확인하기위한 추가 검사가 포함됩니다. 위에서 이것을 파생 :
시작과 끝 날짜, 즉 위해, 밖으로 될 수 있다면, 가능성이있는 경우 startA > endA
또는 startB > endB
, 당신은 또한 순서에 있는지 확인해야합니다 그래서 당신이 두 개의 추가 유효성 규칙을 추가 할 필요가 수단 :
(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)
Start
와 End
의미입니다. Top과 Bottom, East와 West 또는 HighValue와 LoValue라는 두 개의 변수가있는 경우, 값 쌍 중 하나가 반대 변수에 저장되지 않았는지 확인해야합니다. -두 쌍 중 하나만 전환됩니다. 두 쌍의 값을 모두 전환하면 작동합니다.
start
및 end
: 그런 ( "시간의 끝으로"=와 "널 끝" "시간의 처음부터"= "시작 NULL"이라는 의미로)(startA === null || endB === null || startA <= endB) && (endA === null || startB === null || endA >= startB)
DateRangesOverlap = max(start1, start2) < min(end1, end2)
다음과 같은 경우 두 범위가 겹치는 것으로 충분하다고 생각합니다.
(StartDate1 <= EndDate2) and (StartDate2 <= EndDate1)
(StartDate1 <= EndDate2) and (EndDate1 >= StartDate2)
표기법을 이해하기가 쉽다는 것을 알았습니다 . Range1은 항상 테스트에서 왼쪽에 있습니다.
<=
하는 <
경우 시작은 포괄적이고 끝이 배타적입니다.
이 문서의 .NET 용 기간 라이브러리 에서는 열거 형 PeriodRelation에 의한 두 기간의 관계에 대해 설명합니다 .
// ------------------------------------------------------------------------
public enum PeriodRelation
{
After,
StartTouching,
StartInside,
InsideStartTouching,
EnclosingStartTouching,
Enclosing,
EnclosingEndTouching,
ExactMatch,
Inside,
InsideEndTouching,
EndInside,
EndTouching,
Before,
} // enum PeriodRelation
시간적 관계 (또는 다른 간격 관계에 대한 추론)에 대해서는 Allen의 간격 대수를 고려하십시오 . 두 구간이 서로에 대해 가질 수있는 13 가지 가능한 관계를 설명합니다. 다른 참조를 찾을 수 있습니다. "Allen Interval"은 실용적인 검색어 인 것 같습니다. 또한 이러한 작업에 대한 정보는 Snodgrass의 SQL에서 시간 지향적 응용 프로그램 개발 (PDF에서 온라인으로 제공), 날짜, Darwen 및 Lorentzos 시간 데이터 및 관계형 모델 (2002) 또는 시간 및 관계 이론 : 시간 데이터베이스 관계형 모델 및 SQL (2014; 사실상 TD & RM의 두 번째 버전).
짧은 (ish) 답변은 두 개의 날짜 간격 A
과 B
구성 요소 .start
및 .end
제약 조건이있는 .start <= .end
경우 다음 과 같은 경우 두 간격이 겹칩니다.
A.end >= B.start AND A.start <= B.end
중첩 정도에 대한 요구 사항을 충족하도록 >=
vs >
및 <=
vs 의 사용을 조정할 수 있습니다 <
.
ErikE 의견 :
당신이 재미있는 것을 세면 13을 얻을 수있다. 현명한 계산으로, 나는 단지 6을 얻습니다. 그리고 당신이 A 또는 B가 먼저 오는 것을 돌보는다면, 나는 단지 3을 얻습니다 (교차하지 않고, 부분적으로 교차하고, 하나는 완전히 다른 것 안에 있습니다). 15는 다음과 같이 진행됩니다 : [이전 : 전, 시작, 내부, 종료, 후], [시작 : 시작, 내부, 종료, 후], [내 :: 내, 끝, 후], [종료 : 종료, 후], [ 이후 : 후].
나는 'before : before'와 'after : after'의 두 항목을 셀 수 없다고 생각합니다. 역수와의 관계를 동일시하면 7 개의 항목을 볼 수 있습니다 (참조 된 Wikipedia URL의 다이어그램 참조; 7 개의 항목이 있으며 그중 6 개는 다른 역수를 가지며 동일한 수의 역수는 없습니다). 그리고 세 가지가 합리적인지 여부는 요구 사항에 따라 다릅니다.
----------------------|-------A-------|----------------------
|----B1----|
|----B2----|
|----B3----|
|----------B4----------|
|----------------B5----------------|
|----B6----|
----------------------|-------A-------|----------------------
|------B7-------|
|----------B8-----------|
|----B9----|
|----B10-----|
|--------B11--------|
|----B12----|
|----B13----|
----------------------|-------A-------|----------------------
범위가 서로 관련되어있는 위치를 기반으로 다양한 조건을 확인하는 모든 솔루션 은 특정 범위가 더 일찍 시작되도록함으로써 크게 단순화 될 수 있습니다 ! 필요한 경우 먼저 범위를 교체하여 첫 번째 범위가 더 빨리 (또는 동시에) 시작되는지 확인하십시오.
그런 다음 다른 범위 시작이 첫 번째 범위 끝보다 작거나 같은 경우 (범위가 포함 및 시작 시간과 종료 시간을 모두 포함하는 경우)보다 작거나 (범위가 시작 포함 및 종료를 제외한 범위 인 경우) 겹침을 감지 할 수 있습니다. .
양쪽 끝을 모두 포함한다고 가정하면 겹치지 않는 네 가지 가능성 만 있습니다.
|----------------------| 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
(: 두 번째 코드 세그먼트에, 당신은 사용하려는 첫 번째 코드 세그먼트에 대한 문 <
이 아닌 <=
) :
|----------------------| range 1
|---> range 2 overlap
|---> range 2 overlap
|---> range 2 no overlap
|---> range 2 no overlap
범위 1이 범위 2 이후에 시작되지 않도록하여 문제 공간의 절반을 조기에 제거하므로 확인 횟수를 크게 제한합니다.
JavaScript를 사용하는 또 다른 솔루션이 있습니다. 내 솔루션의 전문 분야 :
테스트는 정수를 기반으로하지만 JavaScript의 날짜 객체는 비교할 수 있으므로 두 개의 날짜 객체도 넣을 수 있습니다. 또는 밀리 초 타임 스탬프를 던질 수 있습니다.
/**
* 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));
어디..
증명? 이 테스트 콘솔 코드 gist를 확인하십시오 .
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)은 겹치지 않는 두 개의 열린 간격입니다. 마지막 끝은 끝이 없습니다. 간격이 20을 포함하지 않기 때문에 함수는 true를 반환하지만 간격이 겹치지 않습니다. (단순을 위해 타임 스탬프 대신 사용 된 숫자)
여기에 게시 된 솔루션은 모든 겹치는 범위에서 작동하지 않았습니다 ...
---------------------- | ------- A ------- | ----------- ----------- | ---- B1 ---- | | ---- B2 ---- | | ---- B3 ---- | | ---------- B4 ---------- | | ---------------- B5 ---------------- | | ---- B6 ---- | ---------------------- | ------- A ------- | ----------- ----------- | ------ B7 ------- | | ---------- B8 ----------- | | ---- B9 ---- | | ---- B10 ----- | | -------- B11 -------- | | ---- B12 ---- | | ---- B13 ---- | ---------------------- | ------- A ------- | ----------- -----------
내 작업 솔루션은 다음과 같습니다.
AND ( ( 'start_date'시작 날짜와 종료 날짜 사이)-내부 및 종료 날짜 외부를 제공합니다. 또는 ( 'end_date'시작 날짜와 종료 날짜 사이)-내부 및 시작 날짜 외부를 제공합니다. 또는 ( 'start_date'와 'end_date'사이의 STARTDATE)-날짜가 들어있는 외부 범위에는 하나만 필요합니다. )
이것은 moment.js가있는 내 자바 스크립트 솔루션이었습니다.
// 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
시작 모멘트에 a를 더하여를 정의 할 수도 있습니다 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 ----]
오버랩 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)
기타...
마지막으로 두 간격이 겹치는 일반적인 조건은 다음과 같습니다.
(StartA <🞐 EndB) 및 (EndA> 🞐 StartB)
여기서 🞐는 포함 된 두 끝점을 비교할 때마다 엄격한 불평등을 엄격하지 않은 불평등으로 바꿉니다.
endDate = '0000-00-00'으로 설정하지 않고 아직 끝나지 않은 날짜 범위를 사용하는 경우 (예 : 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가 제공하는 수학적 솔루션은 훌륭하지만 두 가지 세부 사항을 무시합니다.
간격 경계의 닫힌 상태 또는 열린 상태에 대해 닫힌 간격에 유효한 @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;
}
내 의견으로는 가장 쉬운 방법은 EndDate1이 StartDate2 이전이고 EndDate2가 StartDate1 이전인지 비교하는 것입니다.
StartDate가 항상 EndDate 이전의 간격을 고려하는 경우에도 마찬가지입니다.
당신은 이것을 시도 할 수 있습니다 :
//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 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
루비의 경우 나는 이것을 발견했다.
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'))