title: Writing an IsDate() equivalent in C#?
body: <p>Apologies if this has been asked before. I have some data which I need to store as strings, some of that data being dates. The data starts off as strings like "01/02/10" <em>(uk format)</em>. Now, later on, this data is parsed and, depending upon what does the parsing, the results are different (01-Feb-10 vs. 02-Jan-10 for example). Given that the data starts off as strings, before I stored it I would like to say, <em>"if this looks like a date, format it as dd-mmm-yy"</em>.</p>
  
  <p>The trouble being that many things look like a date to the DateTime.Parse() function.</p>
  
  <p>So, I applied some rules and only accept "reasonable" date formats for my checks, and wrote an IsDate() function. I'm seeking suggestions about how to do this because, while it works, my solution seems very clunky.</p>
  
  <p>The whole reason why I did this rather than go down the usual DateTime.TryParse routine is clear if you have ever started throwing random strings at it (like "3/4" and "6.12").</p>
  
  <p>Here's what I have so far:</p>
  
  <pre><code>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&lt;String&gt; AcceptableDateFormats = new List&lt;String&gt;(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;
    }
  }
  </code></pre>
  
  <p>I didn't use the date/time separators from the culture information because I wanted to accept both a "/" and a "-". I guess I could have used the time one though, as that's unlikely to change (for me).</p>