Разбор "25.1235" к дате с использованием InvariantCulture (год из двух цифр) - PullRequest
2 голосов
/ 22 октября 2019

Когда я использую InvariantCulture для разбора строки, оба значения:

var christ1 = DateTime.Parse("12/25/35", CultureInfo.InvariantCulture);

и:

var christ2 = DateTime.ParseExact("12/25/35", "MM/dd/yy", CultureInfo.InvariantCulture);

результат зависит от того, на каком компьютере запущено приложение. На одной машине я получаю эквивалент:

25 декабря 20 35

, а на другой машине я получаю дату на столетие раньше,то есть:

25 декабря 19 35

Что происходит?

1 Ответ

3 голосов
/ 22 октября 2019

(Отвечая на мой собственный вопрос.)

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

В терминах .NET интересующее вас свойство в календаре равно TwoDigitYearMax, поэтому просмотрите CultureInfo.InvariantCulture.DateTimeFormat.Calendar.TwoDigitYearMax или (new GregorianCalendar()).TwoDigitYearMax. Документация по GregorianCalendar.TwoDigitYearMax переопределению .

На компьютере под управлением Windows 10 версии 1809 («Обновление за октябрь 2018», «Redstone 5»), где пользователь не изменил региональные настройки (подробнее очто ниже), свойство TwoDigitYearMax равно 2029, и, как следствие, вы получите 25 декабря 19 35.

Но в Windows 10 версия 1903 («Обновление за май 2019»), «19H1»), то же свойство возвращает 2049, поэтому ваш результат - 25 декабря 20 35.

Однако значение зависит не только от версии Windows. Также имеет значение то, что пользователь вводит в региональных настройках. Так что это на самом деле не «инвариант».

Вы можете изменить год среза на панели управления следующим образом:

  1. Нажмите Пуск , нажмите значок «шестеренка»слева (Настройки) и нажмите Время и язык .
  2. Нажмите Регион слева.
  3. Под Связанные настройки , нажмите Дополнительные дата, время и региональные настройки .
  4. (Вы находитесь в панели управления.) Нажмите Регион .
  5. (Вnew Region window.) Нажмите кнопку Дополнительные настройки ... в нижней части страницы, а в новом окне щелкните вкладку Date .
  6. In Календарь , настройте Когда вводится двузначный год, интерпретируйте его как год между .

В старых версиях Windows это может быть(вставлено из microsoft.com):

  1. Нажмите Пуск , укажите Настройки , а затем нажмите Панель управления .
  2. Дважды щелкните Региональные настройки значок *.
  3. Перейдите на вкладку Дата .
  4. В При вводе двузначного года введите значение года в поле , введитетребуемый год, а затем нажмите OK .

. Или вы можете использовать реестр Windows напрямую, перейти к ключу HKEY_CURRENT_USER\Control Panel\International\Calendars\TwoDigitYearMax и для каждого соответствующего "значения" в этомоставьте неизменным компонент name и отредактируйте компонент data значения (обычное десятичное представление строки) желаемого года среза. Если пользователь никогда не изменял этот параметр на панели управления, две самые внутренние клавиши (Calendars\TwoDigitYearMax) еще не существуют. Применяются обычные предупреждения о смешивании с реестром.

После того, как вы изменили год в Панели управления, каждый процесс .NET, который запустился после внесения этих изменений, будет отражать ваш выбор вСвойство TwoDigitYearMax достигнуто через InvarantCulture!

Так что, если вам нужно согласованное поведение в разных версиях ОС и пользовательских настройках, я думаю, вы не можете использовать InvariantCulture. Вместо этого может сработать что-то подобное:

var tmp = (CultureInfo)(CultureInfo.InvariantCulture.Clone());
tmp.DateTimeFormat.Calendar.TwoDigitYearMax = 2039; // any cutoff you need
 // incorrect: tmp.Calendar.TwoDigitYearMax = 2039
var newInvariantCulture = CultureInfo.ReadOnly(tmp);

, а затем использовать этот экземпляр newInvariantCulture всякий раз, когда вы анализируете даты с двухзначными годами (вы можете поместить его в какое-то поле static readonly).

ПРЕДУПРЕЖДЕНИЕ: Каждый CultureInfo x несет два различных Calendar с, которые могут иметь разные двухзначные максимальные значения года, а именно:

x.DateTimeFormat.Calendar.TwoDigitYearMax
  !=
x.Calendar.TwoDigitYearMax
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...