Liczenie (dat) czy elementy kalendarza się ze sobą zazębiają

Liczenie (dat) czy elementy kalendarza się ze sobą zazębiają
AdamWox
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Jastrzębie-Zdrój
  • Postów: 2180
0

Witam.
Piszę z pytaniem, ponieważ już próbowałem wielu rzeczy i jednak jestem na to za głupi. Potrzebuje nakierowania jak sprawdzić czy dwa elementy kalendarza się zazębiają.

zlecenie_merged.png

To niestety nie działa

Kopiuj

        private bool IsInRange(DateTime start1, DateTime end1, DateTime start2, DateTime end2)
        {
            return (start1 == start2 && end1 == end2) ||
                (start1 < start2 && end1 < end2 && start1 < end2 && end1 > start2) ||
                (start1 > start2 && end1 > end2 && start1 < end2 && end1 > start2) ||
                (start1 > start2 && end1 < end2 && start1 < end2 && end1 > start2) ||
                (start1 < start2 && end1 == end2 && start1 < end2 && end1 > start2) ||
                (start1 == start2 && end1 < end2 && start1 < end2 && end1 > start2);
        }

Większość odpowiedzi na SO jest gdy chce sprawdzić czy data (jedna) zawiera się w przedziale dat. Ja niestety muszę sprawdzić czy przedziały dat się zazębiają. Czy to na zrzucie to nie jest przypadkiem ten warunek start1 == start2 && end1 < end2 && start1 < end2 && end1 > start2?

katakrowa
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Chorzów
  • Postów: 1670
0

Ogólnie do rozważenia masz następujące przypadki ( trzeba jeszcze zdefiniować czy znaki mniejszości / większości są ostre czy nie ).

Kopiuj
Przedział A :                    |-------------------------------------|

Przedziały B różne przypadki:

Przypadek 1 :    |---------| 
Przypadek 2 :               |----------| 
Przypadek 3 :                                 |----------| 
Przypadek 4 :                                                     |----------| 
Przypadek 5 :              |-------------------------------------------------------| 
Przypadek 6 :                                                                        |----------| 

Warto to rozpisać do wyrażenia boolowskiego i zoptymalizować.

AdamWox
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Jastrzębie-Zdrój
  • Postów: 2180
0

Nie będę miał takich przypadków. U mnie jest więcej reguł jak mają być wrzucane appointmenty do kalendarza i jedyne co się może zdarzyć to różne przypadki tego co zaznaczyłem na czerwono w obrębie "jednej linii" (resource), w tym przypadku M3. Zazębianie się na innych zasobach ma zostać. Nie mogę robić dwóch różnych zleceń w tym samym czasie czyli to na czerwono. Jeżeli w tym zakresie dat jest już jakiś wpis to kolejny wpis w tym zasobie powinien się zacząć jak ten poprzedni się skończy.

AdamWox
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Jastrzębie-Zdrój
  • Postów: 2180
0

Ok, chyba też tak miałem. Nie ogarnia przypadku, w którym drugi miałby się zacząć w tej samej godzinie co pierwszy skończył. Na przykład:

ZADANIE 1
Start: 07.10.2020 11:00
End: 07.10.2020 13:00

ZADANIE 2
Start: 07.10.2020 8:00
End: 07.10.2020 11:00

Skoro ZADANIE 2 skończyło się o 11:00 to śmiało ZADANIE 1 może od 11:00 zacząć.

AK
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 3561
0

jest taki paradoksalny (dla mnie - długo wydawał mi się wbrew intuicji) sposób na zaledwie dwóch porównaniach (mi intuicja podpowiadała przynajmniej cztery)

Kopiuj
bool common = range1.start < range2.end && range1.end > range2.start;

Przepracuj sobie sam ostre / nieostre nierówności

katakrowa
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Chorzów
  • Postów: 1670
1

Wg mnie to nie takie oczywiste.
Niech pierwszy przedział dat definiują daty od A1 do A2 a drugi to będą od B1 do B2.

Kopiuj

                                 A1                                    A2
Przedział A :                    |-------------------------------------|
                                 .                                     .
Przedziały B różne przypadki:    .                                     .
                                 .                                     .
                 B1        B2    .                                     .
Przypadek 1 :    |---------|     .                                     .
                            B1   .     B2                              .
Przypadek 2 :               |----------|                               .
                                 .            B1         B2            .
Przypadek 3 :                    .            |----------|             .
                                 .                                B1         B2
Przypadek 4 :                    .                                |----------| 
                            B1   .                                     .     B2
Przypadek 5 :               |------------------------------------------------| 
                                 .                                     .       B1         B2
Przypadek 6 :                    .                                     .       |----------| 

Rozpisujemy poszczególne przypadki:

Kopiuj
1.                B1 <= A1 AND B2 <= A1 AND B1 <= A2 AND B2 <= A2
2.                B1 <= A1 AND B2 >= A1 AND B1 <= A2 AND B2 <= A2
3.                B1 >= A1 AND B2 >= A1 AND B1 <= A2 AND B2 <= A2
4.                B1 >= A1 AND B2 >= A1 AND B1 <= A2 AND B2 >= A2
5.                B1 <= A1 AND B2 >= A1 AND B1 <= A2 AND B2 >= A2
6.                B1 >= A1 AND B2 >= A1 AND B1 >= A2 AND B2 >= A2

Przypadek 1 i 6 nas nie interesują więc pozostają tylko:

Kopiuj
2.                B1 <= A1 AND B2 >= A1 AND B2 <= A2
3.                B1 >= A1 AND B1 <= A2
4.                B1 >= A1 AND B1 <= A2
5.                B1 <= A1 AND B2 >= A2

Teraz uprościmy sobie wyrażenie odpowiednimi podstawieniami. Zamienimy warunki na zmienne logiczne.
Niech:

Kopiuj
              B1 <= A1 = a
              B2 <= A1 = b
              B1 >= A1 = c
              B2 >= A1 = d
              B1 <= A2 = e
              B2 <= A2 = f
              B1 >= A2 = g
              B2 >= A2 = h

Otrzymamy z tego wyrażenie:

Kopiuj

                ( a AND d AND f ) OR ( c AND e ) OR ( c AND e ) OR ( a AND h )
                
                => (adf)+(ce)+(ce)+(ah)
                po zoptymalizowaniu wyjdzie => adf + ce + ah

Czyli końcowy warunek to:

Kopiuj
    ( B1 <= A1 AND B2 >= A1 AND B2 <= A2 ) OR ( B1 >= A1 AND B1 <= A2 ) OR ( B1 <= A1 AND B2 >= A2 )

Po długim wyprowadzeniu i dyskusji w komentarzach jednak trzeba dopisać, że wystarczające i o wiele bardziej optymalne jest:

Kopiuj
( B2 >= A1 AND B1 <= A2 )  
katakrowa
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Chorzów
  • Postów: 1670
1

Jeszcze raz wyprowadzenie tym razem dla wersji optymalnej:

Kopiuj
                                 A1                                    A2
Przedział A :                    |-------------------------------------|
                                 .                                     .
Przedziały B różne przypadki:    .                                     .
                                 .                                     .
                 B1        B2    .                                     .
Przypadek 1 :    |---------|     .                                     .
                            B1   .     B2                              .
Przypadek 2 :               |----------|                               .
                                 .            B1         B2            .
Przypadek 3 :                    .            |----------|             .
                                 .                                B1         B2
Przypadek 4 :                    .                                |----------| 
                            B1   .                                     .     B2
Przypadek 5 :               |------------------------------------------------| 
                                 .                                     .       B1         B2
Przypadek 6 :                    .                                     .       |----------| 

Rozpisujemy poszczególne przypadki:

Kopiuj
1.                B1 <= A1 AND B2 <= A1 AND B1 <= A2 AND B2 <= A2
2.                B1 <= A1 AND B2 >= A1 AND B1 <= A2 AND B2 <= A2
3.                B1 >= A1 AND B2 >= A1 AND B1 <= A2 AND B2 <= A2
4.                B1 >= A1 AND B2 >= A1 AND B1 <= A2 AND B2 >= A2
5.                B1 <= A1 AND B2 >= A1 AND B1 <= A2 AND B2 >= A2
6.                B1 >= A1 AND B2 >= A1 AND B1 >= A2 AND B2 >= A2

Teraz podchodzimy to tematu odwrotnie niż w poprzednim wyprowadzeniu i bierzemy przypadki które nas nie interesują czyli te które nie spełniają naszych założeń. Zatem pozostają tylko:

Kopiuj
1.                B1 <= A1 AND B2 <= A1 AND B1 <= A2 AND B2 <= A2
6.                B1 <= A1 AND B2 <= A1 AND B1 <= A2 AND B2 <= A2

Po wywaleniu warunków "zbędnych" pozostanie:

Kopiuj
1.                B2 < A1
6.                B1 > A2


                  ( B2 < A1 OR B1 > A2 )

Teraz uprościmy sobie wyrażenie odpowiednimi podstawieniami. Zamienimy warunki na zmienne logiczne.
Niech:

Kopiuj
              B2 < A1 = a
              B1 > A2 = b

Otrzymamy wyrażenie wybierające wszystkie przypadki nie spełniające naszego kryterium.

Kopiuj
                ( a OR b ) 

Zatem by uzyskać to co chcemy, czyli zakresy mające część wspólną wystarczy je zanegować:

Kopiuj
                !( a OR b )  =>  ( ~a AND ~b )

Z tetgo wynika że czym jest negacją dla nierówności? Odwrócona nierówność. Odpowiednio podstawiamy i mamy:

Kopiuj
                ( B2 >= A1 AND B1 <= A2 )

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.