Почему DateTime.ToShortTimeString() не учитывает формат Short Time в "Regional and Language Settings"?

У меня возникла проблема, которая, вероятно, связана с моим неправильным пониманием того, как работает метод 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();
}

Update: Основываясь на комментариях Майка ниже, я адаптировал вышеуказанный метод со следующими изменениями:

Следующие две строки

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

Изменено на

string sixAmString = sixAm.ToString("t", culture);
string sixPmString = sixPm.ToString("t", culture);

Я также изменил переменную культуры для использования CultureInfo.CurrentUICulture.

Это, к сожалению, не сработало так хорошо, как я надеялся, вывод вне зависимости от конфигурации Short Time в закладке Windows 7 Formats:

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

Кажется, что CultureInfo.CurrentUICulture всегда en-US.

Ответ 1

В ответ на каждый из моих вопросов:

1) Каково мое непонимание форматов .NET и Windows?

Короткий ответ: связь между параметром "Кратковременное время" в настройках "Региональный и язык" и свойство .NET ShortTimePattern отсутствует. Однако свойство LongTimePattern продиктовано настройкой "Длительное время".

Я адаптировал вышеуказанный метод, заменив две строки форматирования на:

string sixAmString = sixAm.ToString("T", culture.DateTimeFormat);
string sixPmString = sixPm.ToString("T", culture.DateTimeFormat);

Вот результат:

Culture: en-GB, 6AM: 06:00:00, 6PM: 18:00:00 // HH:mm:ss
Culture: en-GB, 6AM: 06:00:00 AM, 6PM: 06:00:00 PM //hh:mm:ss tt

Нижняя часть в этой статье объяснила мне эту проблему.

2) Какое наилучшее решение для создания короткой временной строки (HH: mm или hh: mm tt) на основе настройки операционной системы?

Я не знаю о лучшем решении, но я создал следующую функцию, которая преобразует LongTimeFormat в ShortTimeFormat, что позволяет приложению следовать за параметром users, если они меняют "Long Time" (хотя он не будет отслеживать параметр "Короткое время" ).

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

Результат после внесения указанных изменений:

Culture: en-GB, 6AM: 06:00, 6PM: 18:00
Culture: en-GB, 6AM: 06:00 AM, 6PM: 06:00 PM

Параметр P/Invoke должен использовать GetTimeFormat, передавая TIME_NOSECONDS с использованием DateTime.ToString(Format), как указано выше. Я не тестировал это, так как я бы предпочел не использовать P/Invoke.

Ответ 2

Ответ на второй вопрос:

DateTimeFormat.Format(DateTime.Now, "t", CultureInfo.CurrentUICulture);

или

DateTime.Now.ToString("t", CultureInfo.CurrentUICulture);

На самом деле всегда лучше использовать явные методы, принимающие CultureInfo. Нет никакой последовательности, как .Net выбирает, что использовать по умолчанию либо CurrentCulture, либо CurrentUICulture, либо InvarinatCulture.

Сделать полный ответ. Также я расскажу о различиях между культурами.

Итак, CurrentCulture - "Панель управления → Часы, язык и регион → Регион и язык → вкладка" Форматы ". Это культура, которую вы ожидаете от своих расчетов. Например, вы можете сделать свой учет в США, так что вы должны настроить его в США.

CurrentUICulture - это "Регион и язык → Язык отображения", означает, что когда вы эмигрируете из Украины, вы хотите, чтобы ваше приложение было локализовано в UA (но все вычисления все еще находятся в США).

И InvariantCulture - так называемая культурная агностическая локаль. Вы должны использовать это для хранения информации и так далее. Эффективно это En-US.

Примечание. Я могу ошибаться, когда каждый параметр находится в окнах. Но у вас, вероятно, появилась идея.

Ответ 3

Я уверен, что строка короткого формата времени не используется в DateTime.ToShortTimeString() или DateTime.ToString( "t" ) является ошибкой, поскольку она была исправлена ​​в .NET framework 4.0.