2

Can I alter the standard output format of a DateTime for a specific culture. Example:

class Program
{
    static void Main(string[] args)
    {
        PrintCultureDateTime("ca-ES");
        PrintCultureDateTime("es-ES");
        PrintCultureDateTime("en-US");
        PrintCultureDateTime("en-GB");
        PrintCultureDateTime("pt-PT");
    }

    public static void PrintCultureDateTime(string culture)
    {
        string result = new DateTime(2017, 10, 1).ToString("d", 
            CultureInfo.GetCultureInfo(culture));
        Console.WriteLine(string.Format("{0}: {1}", culture, result));
    }
}

Output:

ca-ES: 1/10/2017
es-ES: 01/10/2017
en-US: 10/1/2017
en-GB: 01/10/2017
pt-PT: 01/10/2017

What I want is to use two digits for day and month using standard "d" format or another standartd one, in order to fix the size of DateTime strings . Something like that output:

ca-ES: 01/10/2017
es-ES: 01/10/2017
en-US: 10/01/2017
en-GB: 01/10/2017
pt-PT: 01/10/2017
Rufus L
  • 36,127
  • 5
  • 30
  • 43
Marc
  • 1,359
  • 1
  • 15
  • 39
  • https://learn.microsoft.com/en-us/dotnet/standard/base-types/standard-date-and-time-format-strings –  Mar 27 '18 at 14:21
  • [Related](https://stackoverflow.com/questions/1202381/using-cultureandregioninfobuilder-to-update-built-in-net-culture) – ProgrammingLlama Mar 27 '18 at 14:23
  • Interestingly I get `01/10/2017` for ca-ES with the code in your example. – Magnus Mar 27 '18 at 14:33
  • @Magnus that's another strange thing, when I use an online c# compiler (like http://rextester.com/l/csharp_online_compiler) it works as you, and on my computer as I post. – Marc Mar 27 '18 at 14:43

3 Answers3

5

You can use DateTimeFormatInfo.ShortDatePattern to get the pattern, and then replace d with dd if you really want to. You might need to consider corner cases such as escaped or quoted d patterns though - as well as obviously not replacing dd with dddd. (Note that the format info from a system culture will be read-only; clone the culture to get one with a read/write format info.) You'd then do the same for months as well, of course. You may even need to change the years part.

It's not clear to me that it's a good idea to do this though - by the time you've changed the format, it's not really "the standard short date format for the culture" any more.

Even after all of this, there's no guarantee that it'll be the same length for all cultures. There's nothing to stop a culture from using a short date format of "'Year:' yyyy '; Month: ' MM '; 'Day: 'dd". It would be highly unusual, but not invalid.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
2

Basing on @Jon Skeet answer I've implemented the following solution. I think that a better regular expression replacement instruction with a single iteration must exist but I've no more time to find it.

It didn't works on format "'Year:' yyyy '; Month: ' MM '; 'Day: 'dd" but I' ll assume the "error".

    public static void PrintCultureDateTime(string culture)
    {
        string result = new DateTime(2017, 10, 1).ToString(FixedSizeShortDatePattern(culture));
        Console.WriteLine(string.Format("{0}: {1}", culture, result));
    }

    public static string FixedSizeShortDatePattern(string culture)
    {
        var cultureInfo = CultureInfo.GetCultureInfo(culture);
        string format = cultureInfo.DateTimeFormat.ShortDatePattern;
        return ReplaceSingleChar(ReplaceSingleChar(format, 'd'), 'M');
    }

    public static string ReplaceSingleChar(string input, char c)
    {
        string cStr = c.ToString();
        string strRegex = string.Format(@"^({0})[^{0}]|[^{0}]({0})[^{0}]|[^{0}]({0})$", cStr);
        return Regex.Replace(input, strRegex, (match) =>
        {
            string token = match.Groups[0].Value;
            if (!string.IsNullOrEmpty(token))
            {
                return match.Value.Replace(cStr, string.Concat(cStr, cStr));
            }
            return token;
        });
    }
Marc
  • 1,359
  • 1
  • 15
  • 39
1

Something like this might work for most date formats, but as Jon Skeet says there might be some weird formats which would be hard to handle.

public class CustomFormatProvider : IFormatProvider
{
    private string _culture;

    public CustomFormatProvider(string culture)
    {
        _culture = culture;
    }

    public object GetFormat(Type formatType)
    {
        if (formatType.Equals(typeof(DateTimeFormatInfo)))
        {
            var format = 
CultureInfo.GetCultureInfo(_culture).DateTimeFormat;
            var info = new DateTimeFormatInfo();
            switch (format.ShortDatePattern.ToString())
            {
                case "d/M/yyyy":
                case "d/MM/yyyy":
                case "dd/M/yyyy":
                case "dd/MM/yyyy":
                    info.ShortDatePattern = "dd/MM/yyyy";
                    return info;
                case "M/dd/yyyy":
                case "MM/dd/yyyy":
                case "M/d/yyyy":
                case "MM/d/yyyy":
                    info.ShortDatePattern = "MM/dd/yyyy";
                    return info;
                default:
                    //This is just example for default handling
                    info.ShortDatePattern = "dd/MM/yyyy";
                    return info;
            }
        }
        else return null;
    }
}

Usage:

public static void PrintCultureDateTime(string culture)
    {
        string result = new DateTime(2017, 10, 1).ToString("d", new 
CustomFormatProvider(culture));
        Console.WriteLine(string.Format("{0}: {1}", culture, result));
    }

Output:

enter image description here

M Bakardzhiev
  • 632
  • 5
  • 13
  • 1
    instead of this big switch case he can simply check if the `format.ShortDatePattern.ToString()` starts with an `m` then use `MM/dd/yyyy` else use `dd/MM/yyyy` much shorter and works for all cases – Franck Mar 27 '18 at 15:25
  • @Franck Yes, it surely can be refactored. – M Bakardzhiev Mar 27 '18 at 15:37
  • As inspiration isn't bad, but it doesn't work on severeal cases as those that haven't '/' as separator or those that start with year. See my solution and comment if you want. – Marc Mar 27 '18 at 16:38