2010-01-04 7 views
6

Ich habe eine Methode, die (manchmal) eine Zeichenfolge im Format "dddd MMMM dd" (Montag Januar 04), die in eine DateTime analysiert werden muss. Ich sage manchmal, weil es auch in "Today" oder "Tomorrow" als Wert übergeben werden kann.Verwenden von DateTime.TryParseExact ohne das Jahr zu kennen

Der Code zu handhaben war einfach genug:

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); 

Das funktionierte bis zur Hälfte bis Dezember. Einige von Ihnen haben wahrscheinlich schon gesehen, was schief gelaufen ist.

Dies wäre an einem Tag im neuen Jahr mit dem Fehler fehlgeschlagen:

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

Es wurde "Monday January 04" geführt zu werden, die für das Jahr 2010 ein gültiges Datum ist, aber nicht im Jahr 2009.

Also meine Frage ist: Gibt es eine Möglichkeit, das Jahr entweder für das laufende Jahr oder das nächste Jahr festzulegen? Gerade jetzt, als quick and dirty fix, ich habe dies:

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."); 

So wird es versuchen, analysieren sie das aktuelle Jahr verwendet wird, und wenn es nicht erfolgreich ist, wird es erneut versuchen, das im nächsten Jahr verwenden. Wenn es danach fehlschlägt, wird es einfach ein ungültiges Datum sein, weil ich mich nur ungefähr 1 Jahr im Voraus sorgen muss, aber wenn jemand eine flexiblere Lösung hat, würde ich es begrüßen. (Beachten Sie, dass ich mich nicht darum kümmern muss, das Datum zu bestätigen, das übergeben wird, es wird entweder für das aktuelle oder das folgende Jahr gültig sein).

Antwort

8

Zuerst sollte Ihr Komponententest dies erfasst haben. Vielleicht möchten Sie die Tests, die Sie für diese Methode geschrieben haben, noch einmal besuchen, um aus dieser Erfahrung zu lernen, wie Sie Ihre Funktionalität besser abdecken können.

Zweitens gibt es einen bestimmten Grund, warum Sie String.Compare anstelle von String.Equals verwenden? Ich halte das folgende besser lesbar:

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

Ich denke, es deutlicher liest, was geschieht (zumal wir müssen nicht daran erinnern, was die endgültige bool Parameter bedeutet in String.Compare).

Jetzt, um das Herz Ihrer Frage zu bekommen. Ihre Methode ist vollkommen in Ordnung und drückt die Logik sehr deutlich aus. Ich würde jedoch eine kleine Refactoring machen:

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 
    ); 
} 

Diese Ihre Methode in zwei verschiedene Stücke von Funktionalität trennt und verhindert, dass sie zu wiederholen (CultureInfo.InvariantCulture und DateTimeStyles.None) macht die Prüfung und Wartung ein wenig leichter. (Sie möchten wahrscheinlich einen besseren Methodennamen als Parse; ich wählte einen kurzen, um zu verhindern, dass die Bildlaufleiste im Codefenster erscheint.)

Als letzte Einschränkung (ohne die Details Ihres Systems zu kennen) möchten Sie vielleicht in Betracht ziehen, auch das Vorjahr zu überprüfen! Stellen Sie sich folgende Situation vor:

  1. Eingabe ist "Donnerstag, 31. Dezember" (gültig für 2009).
  2. System rollt über 1. Januar Grenze in 2010.
  3. Code ausgeführt wird und überprüft, 2010 und 2011, die beide fehlschlagen.

Nur etwas zu berücksichtigen, abhängig von der Art Ihres Systems.

+3

+1000 auf den ersten Absatz. Dies ist ein perfektes Beispiel dafür, wo Unit-Tests das Problem viel früher im Entwicklungszyklus behoben hätten. –

+0

Danke für die ausgezeichnete Antwort. Es gibt Unit-Tests, ich habe dieses Szenario nie in Betracht gezogen :(Es gibt keinen Grund, warum ich eine Methode zum Vergleichen von Strings mit einer anderen verwende. Ich war mir nicht sicher, ob es wichtig war oder nicht. Außerdem muss ich mir keine Sorgen machen Vorige Jahre wie das Auswählen eines Datums in der Vergangenheit ist nicht erlaubt Nochmals vielen Dank – Brandon

+0

Ich brauchte Klammern um (DateTime.Now.Year + 1) sonst endete ich mit einer 1 am Ende meines Jahres, zB 20181 –

Verwandte Themen