.NET 日期到字符串在 Vista 伪文化中给出无效字符串

标签 .net localization internationalization datetime-format pseudolocalization

我的计算机配置的区域性为 not en-US

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

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

This is correct; and is also how Windows renders it:

  • the taskbar

    enter image description here

  • Region and Language settings

    enter image description here

  • Windows Explorer

    enter image description here

  • Outlook

    enter image description here

当我尝试使用当前区域设置将日期转换为 .NET 中的字符串时,例如:

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

我得到的日期不正确:

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

This bug in .NET is evident anyplace in Windows that uses the buggy .NET code:

  • Windows Event Viewer:

    enter image description here

  • Task Scheduler:

    enter image description here

  • SQL Server Management Studio:

    enter image description here

如何使 .NET 没有 bug?

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

Note: The user is allowed to set their Windows to any locale preferences they want. As it is now, my program will not handle valid settings properly. Telling the user, "Don't do that" is pretty mean-spirited.

A similar example comes from Delphi, which assumes that a date separator can never be more than one character. When Windows is configured with a locale that uses multiple characters for the date separator, e.g.:

  • sk-SK (Slovak - Slovakia) : .

where dates should be formatted as:

22. 11. 2011

the code library fails to accept a date separator longer than one character, and falls back to:

22/11/2011

In the past some might suggest that you not to bother with such edge cases. Such suggestions carry no weight with me.

i'll avoid getting into a pissing match with someone who wants to alter the meaning of my question by changing the title. But the question is not limited to pseudo-locales, specifically designed to find bugs in applications.

奖金闲聊

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

  • 11.11.25
  • 2011年11月25日
  • 2011 年 11 月 25 日
  • 2011年11月25日
  • 2011年11月25日。
  • 2011/11/25
  • 2011-11-25
  • 2011
  • 2011年11月25日
  • 2011年11月25日
  • 2011 年 11 月 25 日。
  • 2011 年 11 月 25 日。
  • 2011 年 25 月 11 日
  • 2011 年 11 月 25 日
  • 2011 年 11 月 25 日
  • 2554年11月25日
  • 2011年11月25日
  • 2011年11月25日
  • 32年12月29日

特别有趣的是最后一个例子 doesn't use the gregorian calendar :

  • 阿拉伯语(沙特阿拉伯)ar-SA:29/12/32 02:03:07
  • 迪维希岛(马尔代夫)dv-MV:29/12/32 14:03:07
  • 达里语/普什图语(阿富汗)prf-AF/ps-AF:29/12/32 2:03:07 Ù.

尽管这些都是你永远不必担心的边缘情况。

<小时/>

2011 年 12 月 14 日更新:

该错误的另一个演示是 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 and later: This constant is deprecated. Use LOCALE_SSHORTDATE instead. A custom locale might not have a single, uniform separator character. For example, a format such as "12/31, 2006" is valid.

LOCALE_STIME

Windows Vista and later: This constant is deprecated. Use LOCALE_STIMEFORMAT instead. A custom locale might not have a single, uniform separator character. For example, a format such as "03:56'23" is valid.

最佳答案

此特定错误是由于一些特殊字符的转换造成的,这些特殊字符在 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);
}

关于.NET 日期到字符串在 Vista 伪文化中给出无效字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8234365/

相关文章:

jquery - 使用 JQuery 编写时,变音符号在 Web 应用程序中无法正确呈现

Angular 2+ 本地化 (i18n) rtl 支持

iphone - 确定货币的小数位数

django 翻译模板中的变量内容

Codeigniter 获取语言文件的键

.net - 制作类似于 TinyURL.com 的短网址

.net - 删除 Entity Framework 创建的数据库

.net - 如何找到在运行时作为 Windows 服务运行的 exe 的位置?

c# - 浏览器中的全局化、缓存控制和 HTTP 日期

c# - 在内部而不是浏览器发出请求时获取来源