Escrevendo um equivalente IsDate() em C#?

Peço Desculpa se isto já foi perguntado antes. Eu tenho alguns dados que eu preciso armazenar como strings, alguns desses dados são datas. Os dados começam como strings como "01/02/10" (formato uk) . Agora, mais tarde, estes dados são processados e, dependendo do que faz o processamento, os resultados são diferentes (01-fev-10 vs. 02-Jan-10, por exemplo). Dado que os dados começam como strings, antes de Os armazenar eu gostaria de dizer, " se isto se parece com uma data, formate-o como dd-mmm-AA " .

O problema é que muitas coisas parecem uma data para o DateTime.Função Parse ().

então, eu apliquei algumas regras e só aceito formatos de datas "razoáveis" para minhas verificações, e escrevi uma função IsDate (). Estou procurando sugestões sobre como fazer isso porque, enquanto funciona, minha solução parece muito desajeitada.

A razão de eu ter feito isto, em vez de ir pela data habitual.A rotina de TryParse é clara se alguma vez começou a atirar cordas aleatórias nele (como "3/4" e "6.12").

Eis o que tenho até agora:
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;
  }
}

Eu não usei os separadores de data / hora da Informação da cultura porque eu queria aceitar tanto um " / "e um" -". Eu acho que eu poderia ter usado o tempo um though, como que é improvável mudar (para mim).

Author: Jonathan Leffler, 2010-10-15

9 answers

Verificaste DateTime.TryParse () 's Alternative override where it gives you a lot more control over what it considers to be a date?

 7
Author: Dave Markle, 2010-10-15 13:11:11

Considere a utilização de DateTime.TryParseExact

 6
Author: max, 2010-10-15 13:14:35

Para converter o texto até à data, tanto poderá indicar uma cultura que use esse formato específico : como se quiséssemos converter a data "dd / MM / AAAA" para a data..

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

Ou utilizar o método ParseExact:

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

O método Parsexact só aceita esse formato específico, enquanto o Convert.O método ToDateTime ainda permite algumas variações no formato, e também Aceita alguns outros formatos de data.

Para apanhar dados ilegais, pode utilizar o método 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
} 

Hope below links irá lhe fornecer alguma ajuda:

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

Este é um exemplo para tryParse : http://dotnetperls.com/datetime-tryparse

 6
Author: Dr. Rajesh Rolen, 2010-10-15 13:31:07

Já saiu a tentar {[[0]} sobrecarga que aceita argumentos IFormatProvider e DateTimeStyles? Você pode ser capaz de usar isso para ser mais exigente sobre o que você aceita como uma data real, embora não desnecessariamente jogando exceção apenas para testar as cordas.

 1
Author: Andrew Barber, 2010-10-15 13:13:02

Tenta

DateTime result;
DateTime.TryParseExact(value.ToString(), new string[] { "dd/MM/yyyy", "d/M/yyyy" }, null, DateTimeStyles.None, out result)
 1
Author: sh_kamalh, 2010-10-15 13:22:30

No final, eu fui com uma versão do seguinte:

  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);
  }
 1
Author: Black Light, 2011-04-05 07:34:49
Isto é obviamente uma invasão, mas o que acabei por fazer foi adicionar a referência VisualBasic e usar a função IsDate Em C#:
using Microsoft.VisualBasic;
//...other code...
if (Information.IsDate(YourDateObject)) {
   //...more code...
}
 1
Author: Kevin Pope, 2013-05-31 17:00:13

Em alternativa, poderá ter a sua própria verificação de expressão regular depois de encontrar uma data potencial se necessitar de um maior grau de controlo. algo assim.

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

Abrange xx-yy-zz e xx / yy/zz de acordo com as suas necessidades

 0
Author: Terrance, 2010-10-15 13:19:24
using System.Globalization;

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

Pode usar TryParse no lugar de Parse, Se quiser validar que o argumento é uma data.

 0
Author: shahkalpesh, 2010-10-15 13:30:49