2010-10-15 7 views
6

Wir bitten um Entschuldigung, wenn das schon einmal gefragt wurde. Ich habe einige Daten, die ich als Strings speichern muss, einige davon sind Daten. Die Daten beginnen als Zeichenfolgen wie "01/02/10" (britisches Format). Jetzt, später, werden diese Daten geparst und, abhängig davon, was das Parsing ist, sind die Ergebnisse unterschiedlich (zum Beispiel 01-Feb-10 vs. 02-Jan-10). Da die Daten als Strings beginnen, möchte ich vor der Speicherung sagen: "Wenn das wie ein Datum aussieht, formatiere es als dd-mmm-yy".Schreiben einer IsDate() Entsprechung in C#?

Das Problem ist, dass viele Dinge wie ein Datum für die Funktion DateTime.Parse() aussehen.

Also habe ich einige Regeln angewendet und akzeptiere nur "vernünftige" Datumsformate für meine Prüfungen und schrieb eine IsDate() - Funktion. Ich suche Vorschläge, wie dies zu tun ist, denn während es funktioniert, scheint meine Lösung sehr klobig zu sein.

Der ganze Grund, warum ich dies getan habe, anstatt die übliche DateTime.TryParse-Routine zu durchlaufen, ist klar, wenn Sie jemals angefangen haben, zufällige Zeichenfolgen darauf zu werfen (wie "3/4" und "6.12").

Hier ist, was ich bisher:

class Program 
{ 
    static void Main(string[] args) 
    { 
    Debug.Assert(IsDate(6.12) == false); 
    Debug.Assert(IsDate("3/4") == false); 
    Debug.Assert(IsDate(010210) == false); 
    Debug.Assert(IsDate("010210") == false); 
    Debug.Assert(IsDate("12-jan-2000") == true); 
    Debug.Assert(IsDate("12-12-20") == true); 
    Debug.Assert(IsDate("1/1/34") == true); 
    Debug.Assert(IsDate("09/30/20") == false); 
    Debug.Assert(IsDate(DateTime.Now) == true); 
    } 

    static Boolean IsDate(Object value) 
    { 
    DateTimeFormatInfo DateTimeFormatGB = new CultureInfo("en-GB").DateTimeFormat; // new CultureInfo("en-US").DateTimeFormat; 
    return IsDate(value, DateTimeFormatGB); 
    } 

    static private List<String> AcceptableDateFormats = new List<String>(72); 
    static Boolean IsDate(Object value, DateTimeFormatInfo formatInfo) 
    { 
    if (AcceptableDateFormats.Count == 0) 
    { 
     foreach (var dateFormat in new[] { "d", "dd" }) 
     { 
      foreach (var monthFormat in new[] { "M", "MM", "MMM" }) 
      { 
       foreach (var yearFormat in new[] { "yy", "yyyy" }) 
       { 
       foreach (var separator in new[] { "-", "/" }) // formatInfo.DateSeparator ? 
       { 
        String shortDateFormat; 
        shortDateFormat = dateFormat + separator + monthFormat + separator + yearFormat; 
        AcceptableDateFormats.Add(shortDateFormat); 
        AcceptableDateFormats.Add(shortDateFormat + " " + "HH:mm"); // formatInfo.TimeSeparator 
        AcceptableDateFormats.Add(shortDateFormat + " " + "HH:mm:ss"); 
       } 
       } 
      } 
     } 
    } 

    String sValue = value.ToString().Trim(); 
    DateTime unused; 

    foreach (String format in AcceptableDateFormats) 
    { 
     if (DateTime.TryParseExact(sValue, format, formatInfo, DateTimeStyles.None, out unused) == true) return true; 
    } 

    return false; 
    } 
} 

Ich benutze nicht die Datum/Zeit-Separatoren aus der Kultur Information, weil ich sowohl ein „/“ akzeptieren wollte und ein „-“. Ich denke, ich hätte die Zeit auch nutzen können, da sich das (für mich) wahrscheinlich nicht ändern wird.

+0

Warum nicht DateTime.TryParse verwenden und dann eine Plausibilitätsprüfung durchführen, zum Beispiel für den Jahresteil der zurückgegebenen DateTime? –

Antwort

1

am Ende ging ich mit einer Version der folgenden Möglichkeiten:

static private List<String> AcceptableDateFormats = new List<String>(180); 
    static Boolean IsDate(Object value, DateTimeFormatInfo formatInfo) 
    { 
    if (AcceptableDateFormats.Count == 0) 
    { 
     foreach (var dateFormat in new[] { "d", "dd" }) 
     { 
      foreach (var monthFormat in new[] { "M", "MM", "MMM" }) 
      { 
       foreach (var yearFormat in new[] { "yy", "yyyy" }) 
       { 
       foreach (var separator in new[] { "-", "/", formatInfo.DateSeparator }) 
       { 
        String shortDateFormat; 
        shortDateFormat = dateFormat + separator + monthFormat + separator + yearFormat; 
        AcceptableDateFormats.Add(shortDateFormat); 
        AcceptableDateFormats.Add(shortDateFormat + " " + "HH:mm"); 
        AcceptableDateFormats.Add(shortDateFormat + " " + "HH:mm:ss"); 
        AcceptableDateFormats.Add(shortDateFormat + " " + "HH" + formatInfo.TimeSeparator + "mm"); 
        AcceptableDateFormats.Add(shortDateFormat + " " + "HH" + formatInfo.TimeSeparator + "mm" + formatInfo.TimeSeparator + "ss"); 
       } 
       } 
      } 
     } 
     AcceptableDateFormats = AcceptableDateFormats.Distinct().ToList(); 
    } 

    DateTime unused; 
    return DateTime.TryParseExact(value.ToString(), AcceptableDateFormats.ToArray(), formatInfo, DateTimeStyles.AllowWhiteSpaces, out unused); 
    } 
7

Haben Sie die alternative Überschreibung von DateTime.TryParse() ausgecheckt, wo Sie viel mehr Kontrolle darüber haben, was es als Datum betrachtet?

+0

Es gibt Ihnen nicht viel zusätzliche Kontrolle. –

1

Haben Sie ausgecheckt DateTime.TryParse Überlastung, die IFormatProvider und DateTimeStyles Argumente akzeptiert? Sie können dies möglicherweise verwenden, um wählerischer zu sein, was Sie als tatsächliches Datum akzeptieren, während Sie nicht unnötigerweise nur eine Ausnahme auslösen, um die Strings zu testen.

+0

Ja, habe ich. Ich kann keine Möglichkeit finden, zu verhindern, dass "3/4" oder "6.12" kein Datum ist (und ich keine Ausnahmen erstelle). –

6
+0

Ich dachte, ich hätte es getan. Das Problem ist, dass ich nicht das Format der Daten kontrolliere, aber es ist eine vernünftige Erwartung, dass es ein britisches Formatdatum ist, das vielleicht einen zeitlichen Teil hat. –

6

mit Zeichenfolge konvertieren Sie bis heute entweder eine Kultur angeben, dass bestimmte Format verwendet: wie wollen wir Zeichenfolge Datum "dd/MM/yyyy" to Date ..

datetime mydate = Convert.ToDateTime(
txtdate.Text, CultureInfo.GetCulture("en-GB") 
); 
konvertieren

oder verwenden Sie die ParseExact Methode:

datetime mydate = DateTime.ParseExact(
txtdate.Text, "dd/MM/yyyy", CultureInfo.Invariant 
); 

die ParseExact Methode akzeptiert nur das spezifische Format, während der Convert.ToDateTim Die Methode erlaubt immer noch einige Variationen des Formats und akzeptiert auch andere Datumsformate.

illegale Eingabe zu fangen, können Sie die TryParseExact Methode verwenden:

DateTime d; 
if (DateTime.TryParseExact(txtdate.Text, "dd/MM/yyyy", CultureInfo.Invariant, DateTimeStyles.None, out d)) { 
datetime mydate = d; 
} else { 
// communcate the failure to the user 
} 

ich unten Links hoffen, dass Sie etwas Hilfe liefert:

http://dotnetacademy.blogspot.com/2010/09/convert-string-to-date.html

http://msdn.microsoft.com/en-us/library/system.datetime.tryparse.aspx

http://msdn.microsoft.com/en-us/library/9h21f14e.aspx

http://dotnetacademy.blogspot.com/2009/10/get-current-system-date-format.html

Dies ist ein Beispiel für TryParse: http://dotnetperls.com/datetime-tryparse

+0

Riecht wie Spam. Sie können Ihre eigenen Inhalte bewerben, aber bitte fügen Sie mehr echte Inhalte als nur einen Link zu Ihrem eigenen Blog hinzu. –

+0

@Joel: Ich habe es in meinem Blog viele Monate zurück .. Ich habe auch Links von MSDN ... so kann man nicht sagen, dass –

+0

@Joel: Sorry, ich war nicht wissen, dass die Verknüpfung des eigenen Blogs für Lösung wird nicht beim Stackoverflow akzeptiert. –

0

Alternativ können Sie Ihre eigenen regulären Ausdruck überprüfen, nachdem Sie ein mögliches Datum gefunden, wenn Sie ein höheres Maß an Kontrolle erfordern. etwas wie das.

^(0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])[- /.](19|20)\d\d$ 

deckt xx-yy-zz und xx/yy/zz wie pro Ihre Anforderung

+0

Das Problem ist, mein einfaches Beispiel sucht nach etwa 70 gültigen Datumsformaten. Zugegeben, ein Regex könnte mehr als ein Format erfassen, aber Sie hätten immer noch viele Regex-Strings. Außerdem sehen sie für die meisten Leute wie Linienrauschen aus. : o) –

+0

Es scheint, dass es in diesem Fall keine einfache Antwort gibt. Ihre Suche nach einem größeren Maß an Kontrolle, aber Benutzerfreundlichkeit. Dies ist eher eine Designentscheidung hier. Entweder in Betracht ziehen, die Anzahl der akzeptierten Formate zu beschränken oder ein paar einfache Regex-Prüfungen für Sachen wie "3/4" oder "6" zu kombinieren.12 "und nach der Verwendung von DateTime.TryParse, sobald die Zeichenfolge die Regex-Ausdrücke übergeben hat. – Terrance

+0

Oh und mit regex, Kommentare können einen langen Weg gehen – Terrance

1

DateTime result; 
DateTime.TryParseExact(value.ToString(), new string[] { "dd/MM/yyyy", "d/M/yyyy" }, null, DateTimeStyles.None, out result) 
+0

Hallo, Danke. Ich hatte nicht entdeckt, dass ich ein Array von akzeptablen Formaten übergeben konnte. –

0
using System.Globalization; 

CultureInfo ukCI = CultureInfo.CreateSpecificCulture("en-GB"); 
Console.WriteLine(DateTime.Parse("1/2/2010", ukCI).ToString("dd-MMM-yyyy")); 

Sie versuchen TryParse anstelle von Parse verwenden können, wenn Sie wollen um zu bestätigen, dass das Argument ein Datum ist.

+0

Danke , aber haben Sie sich den Beispielcode angeschaut? –

1

Das ist natürlich ein Hack, aber was ich am Ende tun war die VisualBasic- Referenz hinzufügen und verwenden nur die IsDate Funktion in C#:

using Microsoft.VisualBasic; 
//...other code... 
if (Information.IsDate(YourDateObject)) { 
    //...more code... 
} 
+1

Schön - VB zu referenzieren ist eher ein kulturelles Problem als ein Verteilungs-/Abhängigkeitsproblem. –