2010-01-04 18 views
6

Ho un metodo che (a volte) contiene una stringa nel formato "dddd MMMM dd" (lunedì 04 gennaio) che deve essere analizzata in un DateTime. A volte dico perché potrebbe anche essere passato in "Today" o "Tomorrow" come valore.Utilizzo di DateTime.TryParseExact senza conoscere l'anno

Il codice per gestire questa situazione è stata abbastanza semplice:

if (string.Compare(date, "Today", true) == 0) 
    _selectedDate = DateTime.Today; 
else if (string.Compare(date, "Tomorrow", true) == 0) 
    _selectedDate = DateTime.Today.AddDays(1); 
else 
    _selectedDate = DateTime.Parse(date); 

Questo ha funzionato fino a metà dicembre. Alcuni di voi probabilmente hanno già individuato ciò che è andato storto.

questo sarebbe fallito in qualsiasi data nel nuovo anno con l'errore:

"String was not recognized as a valid DateTime because the day of week was incorrect."

E 'stato sempre superato "Monday January 04" che è una data valida per il 2010, ma non nel 2009.

Quindi il mio domanda è: c'è un modo per impostare l'anno o per l'anno in corso o il prossimo anno? In questo momento, come una soluzione rapida e sporca, ho questo:

if (!DateTime.TryParseExact(date, "dddd MMMM dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out _selectedDate)) 
    if (!DateTime.TryParseExact(date + " " + (DateTime.Now.Year + 1), "dddd MMMM dd yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out _selectedDate)) 
     throw new FormatException("That date is not valid."); 

Quindi tenterà di analizzarlo con l'anno in corso, e se non ha successo si provi ad usare il prossimo anno. Se fallisce, supporterà solo che sia una data non valida, perché devo solo preoccuparmi di un anno di anticipo, ma se qualcuno ha una soluzione più flessibile, lo apprezzerei. (Nota, non devo preoccuparmi di convalidare la data in cui è passato, sarà valido per l'anno corrente o successivo).

risposta

8

In primo luogo, il test dell'unità dovrebbe averlo rilevato. Potresti voler rivisitare i test che hai scritto per questo metodo per imparare da questa esperienza su come coprire le tue funzionalità in modo più approfondito.

In secondo luogo, c'è qualche ragione particolare per cui si utilizza String.Compare anziché String.Equals? Mi consideri il seguente più leggibile:

date.Equals("Today", StringComparison.InvariantCultureIgnoreCase); 

Penso che legge più chiaramente ciò che sta accadendo (soprattutto perché non c'è bisogno di ricordare cosa significa il parametro finale bool in String.Compare).

Ora, per ottenere il cuore della tua domanda. Il tuo metodo è perfettamente valido e esprime molto chiaramente la logica. Vorrei fare una piccola refactoring comunque:

public DateTime ParseInThisYearOrNextYear(string s, out DateTime dt) 
{ 
    if (!Parse(s, "dddd MM dd", out dt)) 
    { 
     if (!Parse(s + " " + DateTime.Now.Year + 1, "dddd MM dd yyyy", out dt)) 
     { 
      throw new FormatException(); 
     } 
    } 

    return dt; 
} 

bool Parse(string s, string format, out DateTime dt) 
{ 
    return DateTime.TryParseExact(
     s, 
     format, 
     CultureInfo.InvariantCulture, 
     DateTimeStyles.None, 
     out dt 
    ); 
} 

Questo separa il metodo in due pezzi distinti di funzionalità e impedisce di ripetere se stessi (CultureInfo.InvariantCulture e DateTimeStyles.None) rendendo collaudo e manutenzione più facile. (Probabilmente vuoi un nome di metodo migliore di Parse; ne ho scelto uno corto per impedire che la barra di scorrimento appaia nella finestra di codice qui.)

Come ultimo avvertimento (senza conoscere i dettagli del tuo sistema) potresti volere considerare anche il controllo dell'anno precedente! Immaginate la seguente situazione:

  1. L'input è "giovedì 31 dicembre" (valido per il 2009).
  2. Rotoli di sistema oltre il limite del 1 gennaio 2010. 2010.
  3. Il codice viene eseguito e le verifiche 2010 e 2011 non vanno a buon fine.

Solo qualcosa da considerare in base alla natura del sistema.

+3

+1000 sul primo paragrafo. Questo è un esempio perfetto di dove il test dell'unità avrebbe risolto il problema molto prima nel ciclo di sviluppo –

+0

Grazie per l'eccellente risposta. Ci sono dei test unitari, non ho mai considerato questo scenario :(Non c'è motivo per cui sto usando un metodo per confrontare le stringhe rispetto a un altro. Non ero sicuro se fosse importante o meno. Inoltre, non ho bisogno di preoccuparmi anni precedenti come la selezione di una data in passato non è consentita.Grazie ancora. – Brandon

+0

Ho bisogno di parentesi intorno (DateTime.Now.Year + 1) altrimenti ho finito con un 1 alla fine del mio anno, ad esempio 20181 –

Problemi correlati