.NET Date to string在Vista Pseudo-cultures中提供无效字符串

时间:2011-11-22 21:55:38

标签: .net localization internationalization datetime-format pseudolocalization

我的计算机配置了not en-US的文化。

使用本机Win32 GetDateFormat函数时,我得到了格式正确的日期:

  • 22 // 11 // 2011 4 :: 42 ::53P̰M]
  

这是正确的;以及Windows如何呈现它:

     
      
  • 任务栏

         

    enter image description here

  •   
  • 区域和语言设置

         

    enter image description here

  •   
  • Windows资源管理器

         

    enter image description here

  •   
  •      

    enter image description here

  •   

当我尝试使用我当前的语言环境将日期转换为.NET中的字符串时,例如:

DateTime.Now.ToString();
DateTime.Now.ToString(CultureInfo.CurrentCulture);

我的日期不正确:

  • 22 //// 11 //// 2011 4 :::: 42 :::: 53P̰M]
  

.NET中的这个错误在使用该错误的Windows中随处可见   .NET代码:

     
      
  • Windows事件查看器:

         

    enter image description here

  •   
  • 任务计划程序:

         

    enter image description here

  •   
  • SQL Server Management Studio:

         

    enter image description here

  •   

我如何让.NET没有错误?

如何使用当前文化(正确)将日期和时间转换为字符串?

  

注意:允许用户将他们的 Windows设置为他们想要的任何区域设置首选项。就像现在一样,我的程序无法处理   有效设置正确。告诉用户,“不要这样做”是非常卑鄙的。

     

一个类似的例子来自Delphi,它假设一个日期   分隔符永远不能超过一个字符。当Windows是   配置了使用多个字符作为日期的区域设置   分隔符,例如:

     
      
  • sk-SK(斯洛伐克 - 斯洛伐克):.
  •   
     

其中日期应格式化为:

22. 11. 2011
     

代码库无法接受长于1的日期分隔符   性格,并回到:

22/11/2011
     

过去有些人可能suggest that you not to bother with such edge cases。这些建议对我没有任何影响。

     

我会避免与想要通过更改标题来改变我的问题含义的人进行一场捣蛋比赛。但问题不仅限于伪语言环境   旨在查找应用程序中的错误。

Bonus Chatter

以下是来自世界各地的日期格式的唯一列表:

  • 25年11月11日
  • 2011年11月25日
  • 2011/11/25
  • 2011.11.25
  • 2011.11.25。
  • 2011/11/25
  • 2011-11-25
      1. 2011
  • 11年11月25日
  • 25.11.2011
  • 25.11.2011г。
  • 25.11.2011。
  • 25 // 11 // 2011
  • 2011年5月25日
  • 25/11/2011
  • 25/11/2554
  • 25-11-11
  • 25-11-2011
  • 29/12/32

特别感兴趣的是doesn't use the gregorian calendar

的最后一个例子
  • 阿拉伯语(沙特阿拉伯)ar-SA:29/12/32 02:03:07م
  • Divehi(马尔代夫)dv-MV:29/12/32 14:03:07
  • Dari / Pashto(阿富汗)prf-AF / ps-AF:29/12/32 2:03:07غ.و

虽然这些是你永远不必担心的边缘情况。


更新14 // 12 // 2011:

该错误的另一个证明是Datetime.Parse无法解析DateTime.ToString

String s = DateTime.Today.ToString("d");   //returns "14////12////2011"
DateTime d = DateTime.Parse(s);            //expects "dd//MM//yyyy"

.Parse会抛出异常。


更新02 // 8,2012 09 :: 56'12:

除了不正确之外,还会删除 日期分隔符 的任何使用。来自MSDN:

  

LOCALE_SDATE

     

Windows Vista及更高版本:不推荐使用此常量。请改用LOCALE_SSHORTDATE。自定义区域设置可能没有单个统一的分隔符。例如,诸如“12 / 31,2006”之类的格式是有效的。

     

LOCALE_STIME

     

Windows Vista及更高版本:不推荐使用此常量。请改用LOCALE_STIMEFORMAT。自定义区域设置可能没有单个统一的分隔符。例如,诸如“03:56'23”之类的格式是有效的。

2 个答案:

答案 0 :(得分:7)

此特定错误是由于某些特殊字符的转换,这些字符未在ShortDatePattern等模式中转义。

ShortDatePattern = "d//MM//yyyy";
模式中的

/表示“插入日期分隔符”,但是当字符串从系统复制到DateTimeFormat结构时,此处已完成扩展(至少在我的系统上)。可悲的是,它缺少一个转义(显然在任何不使用特殊字符作为分隔符的语言中都不可见,并且在英语中不可见,因为它被自身替换)

唯一的解决方案似乎是在DateTimeFormat实例的所有模式中转义分隔符:

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));

以下是所有三种常见案例的完整代码示例

日期到字符串

/// <summary>Convert a date to the short date string in the current locale (e.g. 30//11//2011)</summary>
/// <param name="value">A DateTime to be converted to a short date string</param>
/// <returns>A string containing the localized version of the date</returns>
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);
}

字符串的时间

/// <summary>
/// Convert a time to string using the short time format in the current locale(e.g. 7::21 AM)
/// </summary>
/// <param name="value">A DateTime who's time portion will be converted to a localized string</param>
/// <returns>A string containing the localized version of the time</returns>
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);
}

日期时间到字符串

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

答案 1 :(得分:2)

最好的办法是用MS记录错误,然后创建一个检测这些边缘情况并处理它们的扩展方法。

像这样的东西(在我的头顶):

public static class DateTimeFix
{
    public static string FixedToString(this DateTime value)
    {
        if (IsEdgeCase())
            return FixEdgeCase(value);
        else
            return value.ToString();
    }

    // Edge case logic below
}

然后你使用:

DateTime.Now.FixedToString()

代码。