Почему 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.