Dot-Net

.NET Date to string 在 Vista 偽文化中提供無效字元串

  • November 22, 2011

我的電腦配置的文化不是en-US.

使用本機 Win32GetDateFormat函式時,我得到正確格式的日期:

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

這是對的; 也是 Windows 呈現它的方式:

  • 工作列

在此處輸入圖像描述

  • 區域和語言設置

在此處輸入圖像描述

  • Windows資源管理器

在此處輸入圖像描述

  • 外表

在此處輸入圖像描述

當我嘗試使用我目前的語言環境將日期轉換為 .NET 中的字元串時,例如:

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

我得到一個不正確的日期:

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

.NET 中的這個錯誤在 Windows 中使用有錯誤的 .NET 程式碼的任何地方都很明顯:

  • Windows 事件查看器:

在此處輸入圖像描述

  • 任務調度器:

在此處輸入圖像描述

  • SQL Server 管理工作室:

在此處輸入圖像描述

我如何使 .NET 不出錯?

如何使用目前文化(正確)將日期和時間轉換為字元串?

注意:允許使用者將他們的Windows 設置為他們想要的任何區域設置首選項。就像現在一樣,我的程序將無法正確處理 有效設置。告訴使用者“不要那樣做”是非常卑鄙的。

一個類似的例子來自 Delphi,它假設日期分隔符不能超過一個字元。當 Windows 配置了使用多個字元作為日期分隔符的語言環境時,例如:

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

日期應格式化為:

22. 11. 2011

程式碼庫無法接受超過一個字元的日期分隔符,並回退到:

22/11/2011

在過去,有些人可能會建議您不要為這種邊緣情況而煩惱。這樣的建議對我來說毫無意義。

我會避免與想要通過更改標題來改變我的問題含義的人發生小便比賽。但問題不限於偽語言環境,專門用於查找應用程序中的錯誤。

聊天獎金

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

  • 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
  • 2011 年 11 月 25 日
  • 25.11.2011.
  • 25//11//2011
  • 25/11 2011
  • 25/11/2011
  • 25/11/2554
  • 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:12/29/32 2:03:07 .و

儘管這些是您永遠不必擔心的極端情況。


2011 年 14 月 12 日更新:

該錯誤的另一個展示是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。自定義語言環境可能沒有單個統一的分隔符。例如,“2006 年 12 月 31 日”這樣的格式是有效的。

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

引用自:https://stackoverflow.com/questions/8234365