DateTime && TimeSpan

Lavorare con le date è uno dei compiti più ardui di noi sviluppatori; per fortuna c’è il “DateTime” di .NET che ci offre un valido aiuto.

Definiamo una lista di periodi avente i dati: (DataInizioPeriodo, DataFinePeriodo, InfoPeriodo), quindi definiamo una classe “Period”.
public class Period
{
public DateTime StartDate { get; set; }

public DateTime EndDate { get; set; }

public String Info { get; set; }
}

I periodi presenti nella lista devono verificare le condizioni:

  • Per ognuno di essi la data finale deve essere successiva alla data iniziale.
  • Devono essere disgiunti, quindi due periodi non devono sovrapporsi fra loro.
  • Tra due periodi consecutivi deve passare almeno un intervallo di tempo specificato.

La soluzione adottata prevede tre fasi:

  • Nella prima fase si verifica la validità di ogni periodo.
  • Nella seconda fase si verifica che i periodi siano disgiunti.
  • Nella terza fase si calcola e si verifica l’intervallo di tempo esistente tra i periodi.

Per verificare se ogni periodo sia valido o meno verrà aggiunto un metodo alla classe “Period”.


public Boolean IsValid()
{
return EndDate > StartDate;
}

Per riuscire a determinare se i periodi sono tra loro disgiunti, bisogna verificare che tutti i periodi siano disgiunti a gruppi di due.
Se disponiamo sulla linea del tempo due periodi, otteniamo sei combinazioni possibili come mostrato nell’immagine che segue:

Dall’immagine appare subito evidente che perché due periodi siano disgiunti deve verificarsi la condizione:

  • max(D1, T1) > min(D2, T2) ovvero i periodi indicati con la “X” rossa.

In questo caso possiamo scrivere un metodo che verifichi se due periodi sono effettivamente disgiunti.


private Boolean IsUncouplingPeriods(Period firstPeriod, Period secondPeriod)
{
DateTime maxDateTime = Max(firstPeriod.StartDate, secondPeriod.StartDate);
DateTime minDateTime = Min(firstPeriod.EndDate, secondPeriod.EndDate);

return maxDateTime > minDateTime;
}

Dopo aver verificato che i periodi sono disgiunti tra loro, dobbiamo calcolare l’intervallo di tempo passato tra un periodo e l’altro.
Esso si calcola andando ad eseguire la differenza tra gli estremi di ciascun periodo e verificando che il risultato sia maggiore “dell’intervallo di tempo prefissato”.

  • D1- T2 > intervalloTempoPrefissato
  • D2 – T1 > intervalloTempoPrefissato

Il calcolo indicato sopra è corretto nel caso in cui la lista dei periodi sia ordinata in senso crescente, quindi nel caso in cui non possediamo questa informazione possiamo ordinare la lista oppure applicare la funzione valore assoluto a “intervalloTempoPrefissato” ottenendo le condizioni:

  • D1- T2 > |intervalloTempoPrefissato|
  • D2 – T1 > |intervalloTempoPrefissato|

Anche in questo caso possiamo scrivere un metodo che calcoli e verifichi l’intervallo di tempo tra due periodi:


private Boolean IsIntervalCorrect(Period firstPeriod, Period secondPeriod, Int32 intervalDays)
{
TimeSpan firstTimeSpan = firstPeriod.StartDate.Subtract(secondPeriod.EndDate);
TimeSpan secondoTimeSpan = firstPeriod.EndDate.Subtract(secondPeriod.StartDate);

if ((firstTimeSpan.TotalDays > -intervalDays) && (firstTimeSpan.TotalDays < intervalDays))
return false;

if ((secondoTimeSpan.TotalDays > -intervalDays) && (secondoTimeSpan.TotalDays < intervalDays))
return false;

return true;
}

Per verificare la validità di tutti i periodi basta eseguire un “for” sulla lista dei periodi e chiamare i metodi indicati sopra.


public class ManagerPeriods
{
private IList periodList { get; set; }

public ManagerPeriods(IList periodList)
{
this.periodList = periodList;
}

public Boolean CheckIntervalDaysUncouplingPeriods(Int32 intervalDays)
{
for (int i = 0; i < this.periodList.Count – 1; i++)
{
if ((!this.periodList[i].IsValid()) ||(!this.periodList[i + 1].IsValid()))
return false;

if (!IsUncouplingPeriods(this.periodList[i], this.periodList[i + 1]))
return false;

if (!IsIntervalCorrect(this.periodList[i], this.periodList[i + 1], intervalDays))
return false;
}

return true;
}
}

Dal qui potete scaricarvi il codice

Leave a Reply

Your email address will not be published. Required fields are marked *