Parsing the DateTime format to get Format String

ronag picture ronag · Sep 19, 2013 · Viewed 7.3k times · Source

I would like to be able to get the format string from a DateTime string.

e.g.

"2012-12-08 15:00:00" => "yyyy-MM-dd HH:mm:ss"

"2013/30/01 16:00" => "yyyy/dd/MM HH:mm"

Is this possible?

Answer

Jon Skeet picture Jon Skeet · Sep 19, 2013

It would be very hard to do this in a completely general way, but one option would be to extract the relevant DateTimeFormatInfo that you're interested in (using CultureInfo.DateTimeFormat), extract the culture-specific patterns from that (LongDatePattern, LongTimePattern etc), combine the patterns appropriately in some cases (e.g. ShortDatePattern space ShortTimePattern) and then try each pattern in turn using DateTime.TryParseExact - remembering to still specify the culture each time in order to handle date separators etc appropriately.

When DateTime.TryParseExact returns true, you know you've got a pattern which will parse the given text.

Sample code - including showing an example where you'd expect it to work but it doesn't:

using System;
using System.Collections.Generic;
using System.Globalization;

class Test
{
    static void Main()        
    {
        var us = new CultureInfo("en-US");
        var uk = new CultureInfo("en-GB");
        string text = "07/06/2013 11:22:11";

        // This one fails, as there's no appropriate time format
        Console.WriteLine(GuessPattern(text, us));
        // This one prints dd/MM/yyyy HH:mm:ss
        Console.WriteLine(GuessPattern(text, uk));
    }

    static string GuessPattern(string text, CultureInfo culture)
    {
        foreach (var pattern in GetDateTimePatterns(culture))
        {
            DateTime ignored;
            if (DateTime.TryParseExact(text, pattern, culture,
                                       DateTimeStyles.None, out ignored))
            {
                return pattern;
            }
        }
        return null;
    }

    static IList<string> GetDateTimePatterns(CultureInfo culture)
    {
        var info = culture.DateTimeFormat;
        return new string[]
        {
            info.FullDateTimePattern,
            info.LongDatePattern,
            info.LongTimePattern,
            info.ShortDatePattern,
            info.ShortTimePattern,
            info.MonthDayPattern,
            info.ShortDatePattern + " " + info.LongTimePattern,
            info.ShortDatePattern + " " + info.ShortTimePattern,
            info.YearMonthPattern
            // Consider the sortable pattern, ISO-8601 etc
        };        
    }
} 

You could potentially hard-code some "extra" date and time formats which you expect to work.

EDIT: To handle ambiguity, you could easily make GuessPattern return an IEnumerable<string> instead of a single string:

static IEnumerable<string> GuessPatterns(string text, CultureInfo culture)
{
    DateTime ignored;
    return GetDateTimePatterns(culture)
        .Where(pattern => DateTime.TryParseExact(text, pattern, culture,
                                             DateTimeStyles.None, out ignored))
    }
}