7

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?

Community
  • 1
  • 1
ronag
  • 49,529
  • 25
  • 126
  • 221

4 Answers4

10

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))
    }
}
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • But even if it returns true there might be other patterns that also return true. Then it should fail as ambiguous as OP mentioned in the comments what makes it even harder to return something useful. – Tim Schmelter Sep 19 '13 at 10:19
  • @TimSchmelter: Ah, I hadn't noticed there were additional requirements in the comments. Will edit to address those. – Jon Skeet Sep 19 '13 at 10:25
  • @JonSkeet Jon, your answer really looks good, but I tried it out for a personal use and it turns out that also the call to GuessPattern with the UK culture is fails. I Couldn't find why... – Yair Nevet Sep 20 '13 at 15:33
  • @YairNevet: Whoops, changed the value it was guessing for. Will edit back to sanity :) – Jon Skeet Sep 20 '13 at 15:36
2

You can have a set of predefined formats and parse the date and see if it passes, then you can get the string format you are looking for.

Refer to the answer but its in java - How to get the given date string format(pattern) in java?

Community
  • 1
  • 1
Carbine
  • 7,849
  • 4
  • 30
  • 54
2

I had the same idea as Jon Skeet and went to implement it:

// Helper method
IEnumerable<string> DateTimeFormatPatterns(DateTimeFormatInfo format)
{
    var accessors = new Func<DateTimeFormatInfo, string>[]
    {
        f => f.FullDateTimePattern,
        f => f.LongDatePattern,
        f => f.LongTimePattern,
        f => f.MonthDayPattern,
        f => f.ShortDatePattern,
        f => f.SortableDateTimePattern,
        f => f.UniversalSortableDateTimePattern,
        f => f.YearMonthPattern,
    };

    return accessors.Select(accessor => accessor(format));
}

// The real function
string DetectDateTimeFormat(string date, CultureInfo culture)
{
    DateTime dummy;
    foreach (var pattern in DateTimeFormatPatterns(culture.DateTimeFormat))
    {
        if (DateTime.TryParseExact(date, pattern, culture,
                                   DateTimeStyles.None, out dummy))
        {
            return pattern;
        }
    }

    return null;
}

There is space for improvement here (e.g. the hardcoded DateTimeStyles.None doesn't help, an overload which assumes the current culture would also be useful), but you can use it like this:

var format = DetectDateTimeFormat("2012-12-08 15:00:00",
                                  CultureInfo.CurrentCulture);
Jon
  • 428,835
  • 81
  • 738
  • 806
  • @ronag: Nice, I like the use of `.SingleOrDefault` too. Also, the helper method as I give it above is probably a *liiiiiittle* bit overengineered -- if those accessors are not being used anywhere else, it's much better to just build an array directly like Jon Skeet does. – Jon Sep 19 '13 at 10:38
0

You can try by writing the below code to get yyyy/dd/MM HH:mm format.

DateTimeFormatInfo df1 = new DateTimeFormatInfo();
df1.SortTimePattern();

It would give you same HH:mm format.

Vinoth Krishnan
  • 2,925
  • 6
  • 29
  • 34