.NET Date to string gives invalid strings in Vista Pseudo-cultures

前端 未结 2 1914
醉梦人生
醉梦人生 2021-01-01 12:32

My computer is configured with a culture that is not en-US.

When using the native Win32 GetDateFormat function, i get correctly formatted dates:

  • 22//1
2条回答
  •  夕颜
    夕颜 (楼主)
    2021-01-01 12:43

    This specific bug is due to the transformation of some special characters that aren't escaped in the patterns like ShortDatePattern.

    ShortDatePattern = "d//MM//yyyy";
    

    / in a pattern means "insert the date separator" but here the expansion is already done (at least on my system) when the string is copied from the system to the DateTimeFormat structure. Sadly it is missing an escaping (Obviously not visible on any language not using a special character as a separator and not visible in english as it is replaced with itself)

    The only solution seem to be to escape the separators in all the patterns of the DateTimeFormat instance :

    var c = new System.Globalization.CultureInfo("qps-ploc", true);
    c.DateTimeFormat.ShortDatePattern =
            c.DateTimeFormat.ShortDatePattern.Replace("/", "'/'");
    c.DateTimeFormat.LongTimePattern =
            c.DateTimeFormat.LongTimePattern.Replace(":", "':'");
    Console.WriteLine(DateTime.Now.ToString(c));
    

    Here's full code samples for all three common cases

    Date to string

    /// Convert a date to the short date string in the current locale (e.g. 30//11//2011)
    /// A DateTime to be converted to a short date string
    /// A string containing the localized version of the date
    public static String DateToStr(DateTime value)
    {
        String format = CultureInfo.CurrentCulture.DateTimeFormat.ShortDatePattern;
    
        //The bug in .NET is that it assumes "/" in a date pattern means "the date separator"
        //What .NET doesn't realize is that the locale strings returned by Windows are the Windows format strings. 
        //The bug is exposed in locale's that use two slashes as for their date separator:
        //  dd//MM//yyyy
        // Which .NET misinterprets to give:
        //  30////11////2011
        // when really it should be taken literally to be:
        //  dd'//'MM'//'yyyy
        //which is what this fix does
        format = format.Replace("/", "'/'"); 
    
        return value.ToString(format);
    }
    

    Time to string

    /// 
    /// Convert a time to string using the short time format in the current locale(e.g. 7::21 AM)
    /// 
    /// A DateTime who's time portion will be converted to a localized string
    /// A string containing the localized version of the time
    public static String TimeToStr(DateTime value)
    {
        String format = CultureInfo.CurrentCulture.DateTimeFormat.ShortTimePattern;
    
        //The bug in .NET is that it assumes ":" in a time pattern means "the time separator"
        //What .NET doesn't realize is that the locale strings returned by Windows are the Windows format strings. 
        //The bug is exposed in locale's that use two colons as their time separator:
        //  h::mm::ss tt
        // Which .NET misinterprets to give:
        //  11::::39::::17 AM
        // when really it should be taken literally to be:
        //  h'::'mm'::'ss tt
        //which is what this fix does
        format = format.Replace(":", "':'"); 
    
        return value.ToString(format);
    }
    

    Datetime to string

    /// 
    /// Convert a datetime to a string in the current locale (e.g. 30//11//2001 7::21 AM) 
    /// 
    /// A DateTime to be converted to a general string in the current locale
    /// A string containing the localized version of the datetime
    public static String DateTimeToStr(DateTime datetime)
    {
        return DateToStr(datetime)+" "+TimeToStr(datetime);
    }
    

提交回复
热议问题