2010-10-15 18 views
6

Mi scuso se questo è stato chiesto prima. Ho alcuni dati che ho bisogno di memorizzare come stringhe, alcuni dei quali dati sono date. I dati iniziano come stringhe come "01/02/10" (formato uk). Ora, più avanti, questi dati vengono analizzati e, a seconda di cosa fa l'analisi, i risultati sono diversi (01-Feb-10 vs 02-Jan-10 per esempio). Dato che i dati iniziano come stringhe, prima di memorizzarlo vorrei dire, "se questa sembra una data, formattala come gg-mmm-aa".Scrittura di un equivalente IsDate() in C#?

Il problema è che molte cose sembrano una data per la funzione DateTime.Parse().

Quindi, ho applicato alcune regole e accettato solo i formati di data "ragionevole" per i miei assegni, e ho scritto una funzione IsDate(). Sto cercando suggerimenti su come farlo perché, mentre funziona, la mia soluzione sembra molto goffa.

L'intero motivo per cui ho eseguito questa operazione anziché seguire la solita routine DateTime.TryParse è chiaro se avete mai iniziato a lanciare stringhe casuali (come "3/4" e "6.12").

Ecco quello che ho finora:

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

non ho usato i separatori di data/ora dalle informazioni cultura perché volevo accettare sia un "/" e un "-". Suppongo che avrei potuto usare quello per ora, dato che è improbabile che cambi (per me).

+0

Perché non utilizzare DateTime.TryParse, quindi eseguire un controllo di integrità, ad esempio sulla parte relativa all'anno del DateTime restituito? –

risposta

1

, alla fine, sono andato con una versione di quanto segue:

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

Hai controllato l'override alternativo di DateTime.TryParse() dove ti dà molto più controllo su quella che considera una data?

+0

Non ti dà molto più controllo. –

1

Avete verificato il sovraccarico DateTime.TryParse che accetta gli argomenti IFormatProvider e DateTimeStyles? Potresti essere in grado di usarlo per essere più schizzinosi su ciò che accetti come una data reale, mentre non lanciare inutilmente l'eccezione solo per testare le stringhe.

+0

Sì, ho. Non riesco a trovare un modo per impedirgli di pensare che "3/4" o "6.12" non è una data (e non sto lanciando eccezioni). –

6

considerare l'utilizzo di DateTime.TryParseExact

+0

Pensavo di averlo fatto. Il problema è che non controllo il formato dei dati, ma è ragionevole aspettarsi che sia una data in formato UK che potrebbe o meno avere una parte temporale. –

6

Per convertire la stringa di data che si specificare una cultura che utilizza tale formato specifico: come vogliamo convertire data stringa "dd/MM/yyyy" Fino ad oggi ..

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

oppure utilizzare il metodo ParseExact:

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

procedimento ParseExact che accetta solo formato specifico, mentre il Convert.ToDateTim Il metodo consente comunque alcune varianti del formato e accetta anche altri formati di data.

per la cattura di ingresso illegale, è possibile utilizzare il metodo TryParseExact:

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 
} 

spero di seguito link vi fornirà qualche aiuto:

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

Questo è un esempio per TryParse: http://dotnetperls.com/datetime-tryparse

+0

Odora di spam. Puoi promuovere le tue cose, ma ti preghiamo di includere più contenuti reali di un semplice link al tuo blog. –

+0

@Joel: l'ho postato sul mio blog molti mesi fa .. ho anche fornito link di MSDN ... quindi non si può dire così –

+0

@Joel: Scusate, non sapevo che per fornire il link del proprio blog per la soluzione non è accettata su StackOverflow. –

0

In alternativa si potrebbe avere il proprio assegno espressione regolare dopo aver trovato una data potenziale, se avete bisogno di un maggior grado di controllo. qualcosa di simile.

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

copre xx-yy-zz e xx/yy/zz secondo il vostro requisito

+0

Il problema è che il mio semplice esempio verifica circa 70 formati di data validi. Concessa una regex potrebbe catturare più di un formato, ma avresti ancora un sacco di stringhe regex. Inoltre, per molte persone, sembrano rumore di linea. : o) –

+0

Sembra che in questo caso non ci sia una risposta semplice. La tua ricerca di un maggior grado di controllo ma facilità d'uso. Questa è più una decisione di progettazione qui. Prendi in considerazione la possibilità di limitare il numero di formati accettati o combinare un paio di semplici controlli Regex per cose come "3/4" o "6.12 "e dopo l'uso DateTime.TryParse una volta che la stringa ha passato le espressioni regex – Terrance

+0

Oh e con regex, i commenti possono andare molto lontano – Terrance

1

Prova

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

Ciao, Grazie. Non avevo notato che potevo passare una serie di formati accettabili –

0
using System.Globalization; 

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

È possibile utilizzare TryParse al posto di Parse, se si desidera per verificare che l'argomento sia una data.

+0

Grazie , ma hai guardato il codice di esempio? –

1

Si tratta ovviamente di un hack, ma quello che ho finito per fare era aggiungere il VisualBasic di riferimento e basta usare la funzione IsDate in C#:

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

Nice - e fare riferimento a VB è più un problema culturale che un problema di distribuzione/dipendenza. –