.NET Date to string 在 Vista 伪文化中提供无效字符串 [英] .NET Date to string gives invalid strings in Vista Pseudo-cultures

查看:35
本文介绍了.NET Date to string 在 Vista 伪文化中提供无效字符串的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的计算机配置了一种文化 .这样的建议对我来说毫无意义.

我会避免与想要通过更改标题来改变我的问题含义的人发生争执.但问题不仅限于伪语言环境,特别是旨在发现应用程序中的错误.

奖金聊天

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

  • 11.11.25
  • 2011 年 11 月 25 日
  • 2011 年 11 月 25 日
  • 2011.11.25
  • 2011.11.25.
  • 2011/11/25
  • 2011-11-25
      1. 2011

  • 25.11.11
  • 25.11.2011
  • 25.11.2011 г.
  • 2011 年 11 月 25 日.
  • 25//11//2011
  • 2011 年 11 月 25 日
  • 25/11/2011
  • 2554 年 11 月 25 日
  • 25-11-11
  • 25-11-2011
  • 29/12/32

特别感兴趣的是最后一个不使用公历的例子:

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

虽然这些是您永远不必担心的极端情况.

<小时>

2011 年 14 月 12 日更新:

另外一个bug的演示是Datetime.Parse不能解析DateTime.ToString:

String s = DateTime.Today.ToString("d");//返回14////12////2011"DateTime d = DateTime.Parse(s);//期望dd//MM//yyyy"

.Parse 抛出异常.

<小时>

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

除了不正确之外,日期分隔符 的任何使用都已被弃用.来自 MSDN:

<块引用>

LOCALE_SDATE

Windows Vista 及更高版本:此常量已弃用.使用 LOCALE_SSHORTDATE 代替.自定义语言环境可能没有单个统一的分隔符.例如,2006 年 12 月 31 日"这样的格式是有效的.

LOCALE_STIME

Windows Vista 及更高版本:此常量已弃用.请改用 LOCALE_STIMEFORMAT.自定义语言环境可能没有单个统一的分隔符.例如,03:56'23"这样的格式是有效的.

这个特定的错误是由于在 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>将日期转换为当前语言环境中的短日期字符串(例如 30//11//2011)</summary>///<param name="value">要转换为短日期字符串的日期时间</param>///<returns>包含日期本地化版本的字符串</returns>公共静态字符串 DateToStr(日期时间值){字符串格式 = CultureInfo.CurrentCulture.DateTimeFormat.ShortDatePattern;//.NET 中的错误在于它假定日期模式中的/"表示日期分隔符"//.NET没有意识到Windows返回的语言环境字符串是Windows格式字符串.//错误暴露在使用两个斜杠作为日期分隔符的语言环境中://dd//MM//yyyy//哪些 .NET 会误解://30////11////2011//当它真的应该从字面上理解为://dd'//'MM'//'yyyy//这就是这个修复的作用format = format.Replace("/", "'/'");返回值.ToString(格式);}

字符串时间

///<总结>///使用当前语言环境中的短时间格式将时间转换为字符串(例如 7::21 AM)///</总结>///<param name="value">将时间部分转换为本地化字符串的 DateTime</param>///<returns>包含时间本地化版本的字符串</returns>公共静态字符串 TimeToStr(日期时间值){字符串格式 = CultureInfo.CurrentCulture.DateTimeFormat.ShortTimePattern;//.NET 中的错误在于它假定时间模式中的:"表示时间分隔符"//.NET没有意识到Windows返回的语言环境字符串是Windows格式字符串.//错误暴露在使用两个冒号作为时间分隔符的语言环境中://h::mm::ss tt//哪些 .NET 会误解://11::::39::::17 AM//当它真的应该从字面上理解为://h'::'mm'::'ss tt//这就是这个修复的作用格式 = format.Replace(":", "':'");返回值.ToString(格式);}

日期时间到字符串

///<总结>///将日期时间转换为当前语言环境中的字符串(例如 30//11//2001 7::21 AM)///</总结>///<param name="datetime">要转换为当前语言环境中通用字符串的日期时间</param>///<returns>包含日期时间的本地化版本的字符串</returns>公共静态字符串 DateTimeToStr(DateTime 日期时间){返回 DateToStr(datetime)+" "+TimeToStr(datetime);}

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//11//2011 4::42::53 P̰̃M]

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

  • the taskbar

  • Region and Language settings

  • Windows Explorer

  • Outlook

When i try to convert a date to a string in .NET using my current locale, e.g.:

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

i get an incorrect date:

  • 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:

  • Task Scheduler:

  • SQL Server Management Studio:

How do i make .NET not buggy?

How do i convert dates and times to strings using the current culture (correctly)?

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.

Bonus Chatter

Here's a unique list of date formats from around the world:

  • 11.11.25
  • 11.25.2011
  • 11/25/2011
  • 2011.11.25
  • 2011.11.25.
  • 2011/11/25
  • 2011-11-25
      1. 2011

  • 25.11.11
  • 25.11.2011
  • 25.11.2011 г.
  • 25.11.2011.
  • 25//11//2011
  • 25/11 2011
  • 25/11/2011
  • 25/11/2554
  • 25-11-11
  • 25-11-2011
  • 29/12/32

Of particular interest is the last example which doesn't use the gregorian calendar:

  • Arabic (Saudi Arabia) ar-SA: 29/12/32 02:03:07 م
  • Divehi (Maldives) dv-MV: 29/12/32 14:03:07
  • Dari/Pashto (Afghanistan) prf-AF / ps-AF: 29/12/32 2:03:07 غ.و

Although those are edge cases that you'd never have to worry about.


Update 14//12//2011:

Another demonstration of the bug is that Datetime.Parse cannot parse DateTime.ToString:

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

The .Parse throws an exception.


Update 02//8, 2012 09::56'12:

Any use of a date separator is depricated, in addition to being incorrect. From 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.

解决方案

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

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

Time to string

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

Datetime to string

/// <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 Date to string 在 Vista 伪文化中提供无效字符串的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆