Określ, czy dwa zakresy dat pokrywają się


Biorąc pod uwagę dwa zakresy dat, jaki jest najprostszy lub najskuteczniejszy sposób określenia, czy te dwa zakresy się pokrywają?
Na przykład załóżmy, że mamy zakresy oznaczone zmiennymi DateTime od
StartDate1
do
EndDate1

i

od
StartDate2
do
EndDate2
.
Zaproszony:
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:


(PoczątekA & < = KoniecB) i (KoniecA & > = PoczątekB

)

Dowód

:

Niech Warunek A oznacza DateRange A całkowicie po DateRange B.
_ |---- DateRange A ------| 
|---Date Range B -----| _

(Prawda, jeśli
StartA & > EndB
)
Niech Warunek B oznacza DateRange A całkowicie poprzedza DateRange B
|---- DateRange A -----| _ 
_ |---Date Range B ----|

(Prawda, jeśli
EndA & < StartB
)
Wtedy zachodzi na siebie nakładanie się, jeśli ani A, ani B nie są prawdziwe -

(Jeśli jeden zakres nie występuje całkowicie po drugim,

nie całkowicie przed innym,
wtedy powinny się pokrywać.)
Więc tutaj jest jeden z

prawa de Morgana
https://en.wikipedia.org/wiki/De_Morgan%27s_laws
stwierdza, że:
Not (A Or B)
<=>
Not A And Not B
Co tłumaczy się jako:
(StartA & < = EndB) i (EndA & > = StartB)
UWAGA: Obejmuje to warunki, w których krawędzie dokładnie zachodzą na siebie. Jeśli chcesz to wykluczyć,

zmień instrukcje
& > =
na
& >
i
& < =
na
& <
Uwaga 2: Dzięki @Baodad, zobacz

ten blog
http://baodad.blogspot.com/201 ... .html
faktyczne nakładanie się jest najmniejsze:

{
endA-startA
,
endA - startB
,
endB-startA
,
endB - startB
}
(StartA <= EndB) and (EndA >= StartB)
(StartA <= EndB) and (StartB <= EndA)
Uwaga 3. Dzięki @tomosius, krótsza wersja brzmi:
DateRangesOverlap = max(start1, start2) < min(end1, end2)

W rzeczywistości jest to skrót składniowy do dłuższej implementacji, która obejmuje dodatkowe kontrole, aby upewnić się, że daty rozpoczęcia przypadają na lub przed datami końcowymi. Wyprowadzamy to z góry:
Jeśli daty rozpoczęcia i zakończenia mogą być poza kolejnością, tj. Jeśli jest możliwe, że
startA & > endA
lub
startB & > endB
, powinieneś również sprawdzić, czy są w porządku, oznacza to, że musisz dodać dwie dodatkowe reguły akcji:
(PoczątekA & < = KoniecB) i (PoczątekB & < = KoniecA) i (PoczątekA & < = KoniecA) i (PoczątekB & < = KoniecB)
lub:
(StartA & < = KoniecB) i (PoczątekA & < = KoniecA) i (PoczątekB & < = KoniecA) i (PoczątekB & < = KoniecB)
lub,
(StartA & < = Min (KoniecA, KoniecB) i (PoczątekB & < = Min (KoniecA, KoniecB))
lub:
(Max(StartA, StartB) <= Min(EndA, EndB)
Ale żeby zaimplementować
Min ()
i
Max ()
, musisz napisać jakiś kod (używając potrójnego kodu C dla zwięzłości):
(StartA > StartB? Start A: StartB) <= (EndA < EndB? EndA: EndB)
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Uważam, że wystarczy powiedzieć, że te dwa zakresy pokrywają się, jeśli:
(StartDate1 <= EndDate2) and (StartDate2 <= EndDate1)
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

W tym artykule

biblioteka okresów dla .NET
http://www.codeproject.com/KB/ ... .aspx
opisuje zależność między dwoma okresami czasu, wymieniając

PeriodRelation

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

Anonimowy użytkownik

Potwierdzenie od:

Rozważając rozważania dotyczące związków czasowych (lub wszelkich innych relacji interwałowych, jeśli o to chodzi)

interwał algebra Allena
http://en.wikipedia.org/wiki/A ... ra... Opisuje 13 możliwych relacji, które mogą mieć dwa interwały względem siebie. Możesz znaleźć inne linki - „Allen Interval” wydaje się być operacyjnym hasłem wyszukiwania. Możesz również znaleźć informacje o tych operacjach

w rozwoju aplikacji zorientowanych czasowo w języku SQL Snodgrass (
http://www.cs.arizona.edu/~rts/publications.html
PDF dostępny online pod adresem URL), a także w Date, Darwen i Lorentzos

Temporary Data and the Relational Model
https://rads.stackoverflow.com ... Y0W0E
(2002) lub

Time and Relational Theory: Temporary Databases in the Relational Model and SQL
https://rads.stackoverflow.com ... SNSUG
(2014; właściwie druga edycja TD & RM).
Krótka (ish) odpowiedź: podane dwa zakresy dat
A
i
B
ze składnikami
.start
i
.end
oraz ograniczenie
.start & < = .end
, to te dwa przedziały nakładają się, jeśli:
A.end >= B.start AND A.start <= B.end

Możesz dostosować za pomocą
& > =
kontra
& >
i
& < =
versus
& <
jako zgodnie z wymaganiami do stopnia nakładania się.
ErikE komentuje:

Możesz uzyskać tylko 13, jeśli uważasz, że rzeczy są zabawne ... Mogę uzyskać 15 możliwych relacji, które mogą mieć dwa interwały, kiedy oszaleję. Przy rozsądnej liczbie dostaję tylko sześć, a jeśli odrzucisz obawę, że A lub B jest pierwsze, otrzymam tylko trzy (bez nakładania się, częściowo zachodzenia, jeden całkowicie wewnątrz drugiego). 15 brzmi tak: [38, początek, wnętrze, koniec, po], [39, wnętrze, koniec, po], [40, koniec, po], [41, po], [42].

Myślę, że nie można policzyć dwóch wpisów „przed: przed” i „po: po”. Mogłem zobaczyć 7 wpisów, jeśli zrównasz niektóre relacje z ich inwersjami (zobacz diagram w odnośniku URL Wikipedii; zawiera 7 wpisów, z których 6 ma różne opinie, a równe sobie nie mają wyraźnych opinii). To, czy trzy są rozsądne, zależy od twoich wymagań.
----------------------|-------A-------|----------------------
|----B1----|
|----B2----|
|----B3----|
|----------B4----------|
|----------------B5----------------|
|----B6----|
----------------------|-------A-------|----------------------
|------B7-------|
|----------B8-----------|
|----B9----|
|----B10-----|
|--------B11--------|
|----B12----|
|----B13----|
----------------------|-------A-------|----------------------
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Jeśli konieczne jest obliczenie samego nakładania się, możesz użyć następującego wzoru:
overlap = max(0, min(EndDate1, EndDate2) - max(StartDate1, StartDate2))
if (overlap > 0) {
...
}
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Wszystkie rozwiązania, które testują wiele warunków w oparciu o wzajemne relacje zakresów, można znacznie uprościć.

po prostu upewniając się, że określony zakres zaczyna się wcześniej!

Zapewniasz, że pierwszy zakres rozpocznie się wcześniej (lub w tym samym czasie), zmieniając zakresy z wyprzedzeniem, jeśli to konieczne.
Następnie możesz wykryć nakładanie się, jeśli drugi początek zakresu jest mniejszy lub równy końcowi pierwszego zakresu (jeśli zakresy obejmują zarówno czas rozpoczęcia, jak i zakończenia) lub mniej (jeśli zakresy obejmują początek i wykluczają koniec).
Zakładając inkluzywność na obu końcach, istnieją tylko cztery możliwości, z których jedna się nie pokrywa:
|----------------------| range 1
|---> range 2 overlap
|---> range 2 overlap
|---> range 2 overlap
|---> range 2 no overlap

Punkt końcowy zakresu 2 nie jest w nim zawarty. A więc w pseudokodzie:
def doesOverlap (r1, r2):
if r1.s > r2.s:
swap r1, r2
if r2.s > r1.e:
return false
return true

Można to jeszcze bardziej uprościć:
def doesOverlap (r1, r2):
if r1.s > r2.s:
swap r1, r2
return r2.s <= r1.e

Jeśli zakresy są włączone na początku i wyłączne na końcu, wystarczy zamienić
& >
na
& > =
w drugim
if
(w przypadku kodu pierwszego segmentu: w drugim segmencie należy użyć
& <
, a nie
& < =
):
|----------------------| range 1
|---> range 2 overlap
|---> range 2 overlap
|---> range 2 no overlap
|---> range 2 no overlap

Znacząco ograniczasz liczbę sprawdzeń, które musisz wykonać, ponieważ wcześnie usuwasz połowę problemu, zapewniając, że zakres 1 nigdy nie rozpocznie się po zakresie 2.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Oto inne rozwiązanie wykorzystujące JavaScript. Cechy mojego rozwiązania:
  • Traktuje wartości null jako nieskończoność
  • Zakłada się, że dolna granica obejmuje całość, a górna granica jest wyłączna.
  • W zestawie kilka testów

Testy są oparte na liczbach całkowitych, ale ponieważ obiekty daty JavaScript są porównywalne, możesz po prostu dodać dwa obiekty daty. Możesz też dodać milisekundowy znacznik czasu.

Kod:
>
<pre class="lang-javascript prettyprint-override">
/**
* 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);
}


Testy:
>
<pre class="lang-javascript prettyprint-override">
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);
});
});

Wynik po uruchomieniu z karmą, jaśminem i PhantomJS:

PhantomJS 1.9.8 (Linux): ukończono 20 z 20 SUKCESÓW (0,003 s/0,004 s)
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Oto moje rozwiązanie w

Java

który również działa w nieograniczonych odstępach czasu
<pre class="lang-java prettyprint-override">
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));
}
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

https://i.stack.imgur.com/bDVe1.png
Oto kod, który robi magię:
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));

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

Dowód? Sprawdź ten test

treść kodu konsoli
https://gist.github.com/sandee ... a0b61
.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

zrobiłbym to
StartDate1.IsBetween(StartDate2, EndDate2) || EndDate1.IsBetween(StartDate2, EndDate2)

Gdzie
IsBetween
jest czymś w rodzaju
public static bool IsBetween(this DateTime value, DateTime left, DateTime right) {
return (value > left && value < right) || (value < left && value > right);
}
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Przedstawione tutaj rozwiązanie nie działa dla wszystkich nakładających się zakresów ...
----------------------|-------A-------|----------------------
|----B1----|
|----B2----|
|----B3----|
|----------B4----------|
|----------------B5----------------|
|----B6----|
----------------------|-------A-------|----------------------
|------B7-------|
|----------B8-----------|
|----B9----|
|----B10-----|
|--------B11--------|
|----B12----|
|----B13----|
----------------------|-------A-------|----------------------
moim rozwiązaniem roboczym było:

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.)
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Łatwo byłoby zapamiętać rozwiązanie
min(ends)>max(starts)
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

To było moje rozwiązanie javascript z 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;
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Oto kolejna skrócona odpowiedź za pomocą

momentjs

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

odpowiedź opiera się na powyższych odpowiedziach, ale jest skrócona.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

W Microsoft SQL: funkcja SQL SERVER
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 @OverlapEND
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
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

To rozszerzenie do

doskonała odpowiedź
https://stackoverflow.com/a/325964/2314737
@charles-bretana.
Jednak odpowiedź nie rozróżnia przedziałów otwartych, zamkniętych i półotwartych (lub półotwartych).

Przypadek 1
: A, B - zamknięte przedziały
A = [StartA, EndA]
B = [StartB, EndB] [---- DateRange A ------] (True if StartA > EndB)
[--- Date Range B -----]
[---- DateRange A -----] (True if EndA < StartB)
[--- Date Range B ----]

Nakładające się iff:
(StartA & < = EndB) i (EndA & > = StartB)

Przypadek 2
: A, B-otwarte przedziały
A = (StartA, EndA)
B = (StartB, EndB) (---- DateRange A ------) (True if StartA >= EndB)
(--- Date Range B -----) (---- DateRange A -----) (True if EndA <= StartB)
(--- Date Range B ----)

Nakładające się iff:
(początekA & < koniecB) i (koniecA & > początekB)

Przypadek 3
: A, B otwarte w prawo
A = [StartA, EndA)
B = [StartB, EndB) [---- DateRange A ------) (True if StartA >= EndB)
[--- Date Range B -----) [---- DateRange A -----) (True if EndA <= StartB)
[--- Date Range B ----)

Warunek nakładania się:
(początekA & < koniecB) i (koniecA & > początekB)

Przypadek 4
: A, B pozostawione otwarte
A = (StartA, EndA]
B = (StartB, EndB] (---- DateRange A ------] (True if StartA >= EndB)
(--- Date Range B -----] (---- DateRange A -----] (True if EndA <= StartB)
(--- Date Range B ----]

Warunek nakładania się:
(początekA & < koniecB) i (koniecA & > początekB)

Przypadek 5
: otwieranie z prawej, zamykanie 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 ----]

Warunek nakładania się:
(początek A & < = koniec B) i (koniec A & > początek B)

itp.

..
Wreszcie, ogólny warunek nakładania się dwóch przedziałów to

(StartA & < EndB) i (EndA & > StartB

)
gdzie zamienia ścisłą nierówność w nieścisłą nierówność za każdym razem, gdy dokonuje się porównania między dwoma uwzględnionymi punktami końcowymi.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

najprostsze

Najłatwiejszym sposobem jest użycie dobrze zaprojektowanej biblioteki niestandardowej do pracy z datami i godzinami.
<pre class="lang-java prettyprint-override">
someInterval.overlaps( anotherInterval )


java.time & amp; ThreeTen - opcjonalnie
>
Najlepsze w biznesie są ramy
java.time
https://docs.oracle.com/javase ... .html
zbudowany w Javie 8 i nowszych. Dodaj do tego projektu

ThreeTen-Extra
http://www.threeten.org/threeten-extra/
który rozszerza java.time o dodatkowe klasy, a mianowicie klasę
Interval
http://www.threeten.org/threet ... .html
których potrzebujemy tutaj.
Jeśli chodzi o tag
language-agnostic
w tym pytaniu, kod źródłowy obu projektów jest dostępny do użytku w innych językach (zwróć uwagę na ich licencje).
Interval
>
Klasa
org.threeten.extra.Interval
http://www.threeten.org/threet ... .html
przydatne, ale wymaga momentów czasu i daty (obiekty
java.time.Instant
), a nie tylko wartości daty. Dlatego nadal używamy pierwszej chwili dnia UTC do reprezentowania daty.
<pre class="lang-java prettyprint-override">
Instant start = Instant.parse( "2016-01-01T00:00:00Z" );
Instant stop = Instant.parse( "2016-02-01T00:00:00Z" );

Utwórz
Interval
, aby przedstawić ten przedział czasu.
<pre class="lang-java prettyprint-override">
Interval interval_A = Interval.of( start , stop );

Możemy również zdefiniować
Interval
z punktem początkowym plus
Duration
http://docs.oracle.com/javase/ ... .html
.
<pre class="lang-java prettyprint-override">
Instant start_B = Instant.parse( "2016-01-03T00:00:00Z" );
Interval interval_B = Interval.of( start_B , Duration.of( 3 , ChronoUnit.DAYS ) );

Porównanie z testem nakładania się jest łatwe.
<pre class="lang-java prettyprint-override">
Boolean overlaps = interval_A.overlaps( interval_B );

Możesz porównać
Interval
http://www.threeten.org/threet ... .html
z innym
Interval
http://www.threeten.org/threet ... .html
lub
Instant
http://docs.oracle.com/javase/ ... Dtrue
:

Wszyscy używają metody
Half-Open
do określenia przedziału czasu, w którym następuje początek

włącznie

a koniec jest

Ekskluzywny

.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

W przypadku korzystania z zakresu dat, który jeszcze się nie zakończył (nadal trwa), na przykład nie został ustawiony
endDate = '0000-00-00' nie możesz użyć BETWEEN, ponieważ 0000-00-00 nie jest prawidłową datą!
Użyłem tego rozwiązania:
(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

Jeśli data początkowa2 jest wyższa, daty końcowe nie pokrywają się!
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Odpowiedź jest dla mnie zbyt prosta, dlatego stworzyłem bardziej ogólną dynamiczną instrukcję SQL, która sprawdza, czy dana osoba ma jakieś nakładające się daty.
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)
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Rozwiązanie matematyczne podane przez @Bretana jest dobre, ale pomija dwa konkretne szczegóły:
  • aspekt rozstawu zamkniętego lub półotwartego
  • puste miejsca

W stanie zamkniętym lub otwartym granic przedziałów czasowych rozwiązanie problemu @ Bretany jest dopuszczalne

na zamknięte okresy
(PoczątekA & < = KoniecB) i (KoniecA & > = PoczątekB)

można przepisać

na półotwarte przerwy

do:

(PoczątekA & < KoniecB) i (KoniecA & > PoczątekB)

Ta korekta jest konieczna, ponieważ otwarta granica przedziału z definicji nie jest częścią zakresu wartości przedziału.
Jeśli chodzi o

puste miejsca
, to tutaj związek pokazany powyżej nie zachowuje się jak NIE. Puste przedziały, które z definicji nie zawierają żadnej prawidłowej wartości, należy traktować jako przypadek specjalny. Demonstruję to w mojej bibliotece czasu Java

Time4J
https://github.com/MenoData/Time4J
w tym przykładzie:
MomentInterval a = MomentInterval.between(Instant.now(), Instant.now().plusSeconds(2));
MomentInterval b = a.collapse();// make b an empty interval out of aSystem.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)

Przedni nawias kwadratowy „[” oznacza zamknięty początek, a ostatni nawias „)” oznacza otwarty koniec.
System.out.println( "startA < endB: " + a.getStartAsInstant().isBefore(b.getEndAsInstant()));// false
System.out.println( "endA > startB: " + a.getEndAsInstant().isAfter(b.getStartAsInstant()));// trueSystem.out.println("a overlaps b: " + a.intersects(b));// a overlaps b: false

Jak pokazano powyżej, puste przęsła naruszają powyższy warunek nakładania się (zwłaszcza startA & < endB), więc Time4J (i inne biblioteki) musi traktować to jako specjalny przypadek krawędzi, aby upewnić się, że dowolne odstępy nie nakładają się na puste odstępy. Oczywiście przedziały dat (które są domyślnie zamknięte w Time4J, ale mogą być półotwarte lub puste) są obsługiwane w podobny sposób.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Moim zdaniem najłatwiejszym sposobem na to byłoby porównanie, jeśli albo EndDate1 jest przed StartDate2, a EndDate2 jest przed StartDate1.
Dzieje się tak, oczywiście, jeśli rozważasz odstępy czasu, w których StartDate jest zawsze przed EndDate.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Oto ogólna metoda, która może być przydatna lokalnie.
// 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
*/
}
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

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");
}
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Oto co zrobiłem za pomocą narzędzia util.Date w języku Java.
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;
}
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Miałem sytuację, w której zamiast godzin mieliśmy daty, a daty mogły pokrywać się tylko z przykładem początku/końca. poniżej:
https://i.stack.imgur.com/qzRBx.png
(Zielony to bieżący interwał, niebieskie bloki to interwały, czerwone to nakładające się interwały).
Dopasowałem odpowiedź Iana Nelsona do następującego rozwiązania:
(startB <= startA && endB > startA)
|| (startB >= startA && startB < endA)

To pasuje do wszystkich przypadków pokrywania się, ale ignoruje dozwolone przypadki nakładania się.

Aby odpowiedzieć na pytania, Zaloguj się lub Zarejestruj się