为什么DateTime.ToShortTimeString()不遵循"区域和语言设置"中的短时格式?

Ric*_*ter 10 .net formatting time datetime cultureinfo

我遇到了一个问题,可能是由于我对DateTime.ToShortTimeString()方法如何工作的误解.使用此函数格式化时间字符串时,我假设它将遵循Windows 7格式设置中的"短时间"设置

Control Panel -> Clock, Language and Region -> Region and Language -> Formats Tab.

然而,.NET似乎选择了一种不基于此设置的短时间格式,而是基于当前的文化:

Region and Language -> Location -> Current Location

我在Windows 7 RC上做了一些测试:

Culture: en-GB, 6AM: 06:00, 6PM: 18:00 // HH:mm (United Kingdom)
Culture: en-GB, 6AM: 06:00, 6PM: 18:00 // hh:mm (United Kingdom)
Culture: en-US, 6AM: 6:00 AM, 6PM: 6:00 PM // HH:mm (United States)
Culture: en-US, 6AM: 6:00 AM, 6PM: 6:00 PM // hh:mm (United States)
Culture: el-GR, 6AM: 6:00 ??, 6PM: 6:00 ?? // HH:mm (Greece)
Culture: el-GR, 6AM: 6:00 ??, 6PM: 6:00 ?? // hh:mm (Greece)

我使用el-GR作为报告问题的用户的文化,他也在Vista SP2和Win 7 RC上测试了相同的结果.

问题是双重的:1)我对.NET和Windows格式的误解是什么?2)根据操作系统创建短格式时间字符串(HH:mm或hh:mm tt)的最佳解决方案是什么,理想情况下这应该在Mono中工作,所以我宁愿避免从注册表或P/Invoke中读取.

用于生成上述方法的方法,供将来参考和测试.

[STAThread]
static void Main(string[] args)
{
    CultureInfo culture = CultureInfo.CurrentCulture;

    DateTime sixAm = new DateTime(2009, 07, 05, 6, 0, 0); // 6AM 
    DateTime sixPm = new DateTime(2009, 07, 05, 18, 0, 0); // 6PM

    string sixAmString = sixAm.ToShortTimeString();
    string sixPmString = sixPm.ToShortTimeString();

    string format = "Culture: {0}, 6AM: {1}, 6PM: {2}";

    string output = String.Format(format, culture, sixAmString, sixPmString);
    Console.WriteLine(output);
    Clipboard.Clear();
    Clipboard.SetText(output);

    Console.ReadKey();
}
Run Code Online (Sandbox Code Playgroud)

更新: 根据迈克的评论,我采用以下方法修改了上述方法:

以下两行

string sixAmString = sixAm.ToShortTimeString();
string sixPmString = sixPm.ToShortTimeString();
Run Code Online (Sandbox Code Playgroud)

变成

string sixAmString = sixAm.ToString("t", culture);
string sixPmString = sixPm.ToString("t", culture);
Run Code Online (Sandbox Code Playgroud)

我还将culture变量更改为使用CultureInfo.CurrentUICulture.

这不幸的是没有工作,以及我所希望的,在Windows 7中的格式选项卡中的输出,无论时间短的配置是:

Culture: en-US, 6AM: 6:00 AM, 6PM: 6:00 PM

看起来CultureInfo.CurrentUICulture始终是en-US.

Mik*_*liy 5

回答你的第二个问题是

DateTimeFormat.Format(DateTime.Now, "t", CultureInfo.CurrentUICulture);
Run Code Online (Sandbox Code Playgroud)

要么

DateTime.Now.ToString("t", CultureInfo.CurrentUICulture);
Run Code Online (Sandbox Code Playgroud)

使用接受CultureInfo的显式方法实际上总是更好.没有一致性.Net选择默认使用的是CurrentCulture或CurrentUICulture或InvarinatCulture.

使答案充分.我还将概述不同文化之间的差异.

所以CurrentCulture是"控制面板 - >时钟,语言和区域 - >区域和语言 - >格式选项卡".这是您期望计算的文化.例如,您可以在美国进行会计处理,因此您可以在美国进行配置.

CurrentUICulture是"区域和语言 - >显示语言",意味着当您从乌克兰移民时,您希望您的应用程序在UA中本地化(但所有计算仍在美国).

InvariantCulture是所谓的文化不可知的语言环境.您应该使用它来存储信息等.实际上它是En-US.

注意:我在Windows中的每个设置都可能出错.但你可能有了一个主意.


Ric*_*ter 1

回答我的每个问题:

1) 我对 .NET 和 Windows 格式的误解是什么?

简而言之,“区域和语言”设置中的“短时间”设置与 .NET 的 ShortTimePattern 属性之间没有链接。然而,LongTimePattern 属性由“Long Time”设置决定。

我调整了上述方法,将两条格式化行替换为:

string sixAmString = sixAm.ToString("T", culture.DateTimeFormat);
string sixPmString = sixPm.ToString("T", culture.DateTimeFormat);
Run Code Online (Sandbox Code Playgroud)

这是输出:

文化:en-GB,上午 6 点:06:00:00,下午 6 点:18:00:00 // HH:mm:ss
文化:en-GB,上午 6 点:06:00:00 AM,下午 6 点:06:00:00 PM //hh:mm:ss tt

这篇文章的底部向我解释了这个问题。

2) 根据操作系统设置创建短格式时间字符串(HH:mm 或 hh:mm tt)的最佳解决方案是什么?

我不知道最好的解决方案,但我创建了以下函数,将 LongTimeFormat 转换为 ShortTimeFormat,从而允许应用程序在更改“Long Time”时遵循用户选项(尽管它不会跟踪“Short TimeFormat”)时间设定)。

static string GetShortTimeString(DateTime ShortTimeString)
{
    DateTimeFormatInfo dateTimeFormat = CultureInfo.CurrentCulture.DateTimeFormat;
    string ShortTimePattern = dateTimeFormat.LongTimePattern.Replace(":ss", String.Empty);
    ShortTimePattern = ShortTimePattern.Replace(":s", String.Empty);

    return ShortTimeString.ToString(ShortTimePattern);
}
Run Code Online (Sandbox Code Playgroud)

进行上述更改后的输出:

文化:en-GB,上午 6 点:06:00,下午 6 点:18:00
文化:en-GB,上午 6 点:06:00 AM,下午 6 点:06:00 PM

P/Invoke 选项是使用GetTimeFormat,并使用上面的 DateTime.ToString(Format) 传递 TIME_NOSECONDS。我还没有对此进行测试,因为我宁愿避免使用 P/Invoke。