[PHP] Calcolare se due intervalli di tempo si sovrappongono

Maures

Utente Attivo
25 Mar 2015
45
0
0
Buongiorno a tutti,
sto cercando un modo per ottimizzare un if ed evitarmi numerosi OR e AND.
Ho a disposizione due date e orario (formato: 2015-05-20 16:15:00); già inserite e dovrei controllare se una seconda coppia si intersechi o meno con la prima.

con la funzione strtotime converto tutte e quattro le date nei relativi timestamp, ma non riesco a trovare un modo per trovare un'intersezione.

I casi sono molti perché, oltre ai casi in cui una delle due date sia all'interno della coppia iniziale, ci sono anche i casi in cui la seconda coppia è contenuta completamente nella seconda e viceversa.

Si accettano consigli per evitare il più lungo if della storia della programmazione php!
 

marino51

Utente Attivo
28 Feb 2013
2.874
154
63
Lombardia
spero di non essermi incasinato con qualche maggiore o minore
se le date di riferimento sono in una tabella del db, si può agire direttamente
con una query che fornisce i risultati
altrimenti è necessario agire nello script considerando che,
i casi possibili dovrebbero essere 4 definiti e riportati per chiarezza, separatamente

dataINIZIO e dataFINE periodo definito
dataDA e dataA periodo da verificare

il primo caso, periodo da verificare sovrapposto al periodo definito
PHP:
dataINIZIO <= dataDA AND dataA <= dataFINE
il secondo caso, periodo da verificare sovrapposto solo nella parte iniziale
PHP:
dataINIZIO <= dataDA AND dataDA <= dataFINE AND dataA > dataFINE
il terzo caso, periodo da verificare sovrapposto solo nella parte finale
PHP:
dataDA < dataINIZIO AND dataINIZIO <= dataA AND dataA <= dataFINE
il quarto caso, il periodo da verificare deborda il periodo definito
PHP:
dataDA<dataINIZIO AND dataA>dataFINE
i quattro casi messi in OR forniscono "vero"/"falso"

ho considerato che le date sono coerenti tra loro (inizio/fine e da/a) quindi controllate a monte

fai sapere se ok
ciao
Marino
 

Maures

Utente Attivo
25 Mar 2015
45
0
0
spero di non essermi incasinato con qualche maggiore o minore
se le date di riferimento sono in una tabella del db, si può agire direttamente
con una query che fornisce i risultati
altrimenti è necessario agire nello script considerando che,
i casi possibili dovrebbero essere 4 definiti e riportati per chiarezza, separatamente

dataINIZIO e dataFINE periodo definito
dataDA e dataA periodo da verificare

il primo caso, periodo da verificare sovrapposto al periodo definito
PHP:
dataINIZIO <= dataDA AND dataA <= dataFINE
il secondo caso, periodo da verificare sovrapposto solo nella parte iniziale
PHP:
dataINIZIO <= dataDA AND dataDA <= dataFINE AND dataA > dataFINE
il terzo caso, periodo da verificare sovrapposto solo nella parte finale
PHP:
dataDA < dataINIZIO AND dataINIZIO <= dataA AND dataA <= dataFINE
il quarto caso, il periodo da verificare deborda il periodo definito
PHP:
dataDA<dataINIZIO AND dataA>dataFINE
i quattro casi messi in OR forniscono "vero"/"falso"

ho considerato che le date sono coerenti tra loro (inizio/fine e da/a) quindi controllate a monte

fai sapere se ok
ciao
Marino
più o meno era come ho fatto, ma l'if risultava molto "ingombrante".
facendomi qualche disegnino sono riuscito a ridurlo a questo:

Codice:
if((($inseritaDa >= $presenteDa AND $inseritaDa < $presenteA) OR ($inseritaA > $presenteDa AND $inseritaA <= $presenteA)) OR ($inseritaDa <= $presenteDa AND $inseritaA >= $presenteA))
che mi prende tutti i casi:
- se inseritaDa o inseritaA sono compresi tra gli estremi dell'intervallo da presenteDa e presenteA ==> overlap
- se inseritaDa e inseritaA sono esterni all'intervallo presenteDa e presenteA ==> overlap
- ho aggiunto anche gli uguali per i casi in cui uno degli estremi inseriti (o entrambi) siano uguali a quelli già presenti.
 

marino51

Utente Attivo
28 Feb 2013
2.874
154
63
Lombardia
si, è una semplificazione di quanto ti ho suggerito,
se ti interessa solo la sovrapposizione, va bene
se vuoi altro (esempio, calcolo prezzi variabili con il periodo) non ti basta
ciao
Marino
 

old_fan

Nuovo Utente
27 Gen 2017
2
1
3
Non so se ancora interessa una risposta, però a volte è più comodo 'negare' i casi complementari.
Gli eventi non si sovrappongono in questi casi:
A)
evento 1: +++++++_________________
evento 2: _______________++++++++
B)
evento 1: _______________++++++++
evento 2: +++++++______________

Probabilmente dipende dai casi, ma a me è bastato controllare

NOT (ev1_fine < ev2_inizio OR ev2_fine < ev1_inizio)
 
  • Like
Reactions: marino51

marino51

Utente Attivo
28 Feb 2013
2.874
154
63
Lombardia
Probabilmente dipende dai casi, ma a me è bastato controllare
spero di non aver dimenticato dei casi possibili, ma quanto hai suggerito funziona nelle varie situazioni,
qui il risultato (le due condizioni separate, sono messe in positivo e stampate per vedere il loro comportamento)
https://jsfiddle.net/301yxhs1/

ora la domanda, superando la prova pratica, quale "dimostrazione" porta a definire che le due condizioni sono sufficienti ?
 

old_fan

Nuovo Utente
27 Gen 2017
2
1
3
Boh...
In realtà non ho una "dimostrazione" matematica che mi 'certifica' il risultato.

Però, se a logica non erro, la sequenza di due eventi temporali >disgiunti<, nel caso semplificato che si sappia a priori che l'evento "ev2" sia successivo all'evento "ev1" (ovvero che comunque ev1_inizio <= ev2_inizio), può essere rappresentata così:
+++ev1+++________++ev2++
L'unica condizione per avere conferma se sono disgiunti, è che l'inizio di ev2 non deve toccare nessun punto di ev1, ovvero (dato il caso semplificato) che ev1_fine < ev2_inizio. Non sono disgiunti in tutti gli altri casi: NOT (ev1_fine < ev2_inizio).

Tolta la semplificazione sulla consequenzialità, devo similarmente controllare anche il 2° caso, ovvero che l'evento "ev1" sia successivo a "ev2":
++ev2++________+++ev1+++
Quindi: NOT (ev2_fine < ev1_inizio)

Le due condizioni devono essere contemporaneamente vere

NOT (ev1_fine < ev2_inizio) AND NOT (ev2_fine < ev1_inizio)
ovvero
NOT (ev1_fine < ev2_inizio OR ev2_fine < ev1_inizio)

Forse sulla "dimostrazione" formale ci devo lavorare ancora un po' ;-) .
 
Ultima modifica: