Почему DateTime не может выполнять DateTime.ParseExact?

Во время борьбы с проблемами форматирования DateTime.ParseExact я решил передать ParseExact из put из DateTime.ToString(), например:

DateTime date2 = new DateTime(1962, 1, 27);
string[] expectedFormats = { "G", "g", "f", "F", "D", "d", "M/d/yyy", "MM/dd/yyy", "MM-dd-yyy", "MMM dd, yyy", "MMM dd yyy", "MMMM dd, yyy", "MMMM dd yyy" };
bool parsed = false;

foreach (string fmt in expectedFormats)
{
    try
    {
        DateTime dtDateTime = DateTime.ParseExact(date2.ToString(fmt), fmt, new CultureInfo("en-US"));
        parsed = true;
    }
    catch (Exception)
    {
        parsed = false;
    }

    Console.WriteLine("[{0}] {1}", parsed,date2.ToString(fmt));
}

Это вывод:

[True] 1/27/1962 12:00:00 AM
[True] 1/27/1962 12:00 AM
[True] Saturday, January 27, 1962 12:00 AM
[True] Saturday, January 27, 1962 12:00:00 AM
[True] Saturday, January 27, 1962
[True] 1/27/1962
[False] 1/27/1962
[False] 01/27/1962
[False] 01-27-1962
[False] Jan 27, 1962
[False] Jan 27 1962
[False] January 27, 1962
[False] January 27 1962

Что мне нужно сделать, чтобы ParseExact обрабатывал строки пользовательского формата? Я ошибаюсь, чтобы ожидать, что DateTime сможет использовать собственный вывод на основе той же строки формата?

Ответы

Ответ 1

Это наглядно демонстрирует, что DateTime.ParseExact не является безопасным в обратном направлении с помощью Datetime.ToString. Я не уверен, что это большой ответ, но проблема определенно связана с 3-значным годом формата yyy. С 1962 года невозможно представить в 3-х цифрах ToString вынужден использовать 4 цифры. По-видимому, ParseExact недостаточно умен, чтобы отменить эту логику и вместо этого ищет ровно 3 цифры. Обходным путем является использование yyyy вместо yyy. Я хотел бы представить это как ошибку для веб-сайта Microsoft Connect и посмотреть, что из этого выйдет.

Ответ 2

Я удивлен, увидев это, но документация в msdn говорит:

Вы можете указать один из стандартных спецификаторов формата даты и времени или ограниченную комбинацию специализированного спецификатора формата даты и времени

http://msdn.microsoft.com/en-us/library/2h3syy57.aspx

Обновление

Вы можете использовать обходное решение, упомянутое в предыдущем ответе.

Ответ 3

Я взял ваш код, и изменить "yyy" на "yyyy" достаточно, чтобы вернуть "TRUE" для всех (сначала воспроизведя "FALSE", прежде чем я внес какие-либо изменения).

Документация в MSDN неясна, но подчеркивает необходимость указания полной ширины каждого компонента (например, yyyy, а не yyy) без инвариантной культуры:

http://msdn.microsoft.com/en-us/library/w2sa9yss.aspx

Если формат представляет собой шаблон пользовательского формата, который не включает разделители даты или времени (например, "yyyyMMdd HHmm" ), используйте культуру инварианта для параметра поставщика и самую широкую форму каждого спецификатора специального формата. Например, если вы хотите указать часы в шаблоне формата, укажите более широкую форму "HH" вместо более узкой формы "H".

Ответ 4

Microsoft внедрила строковый формат для округления даты DateTime. Вы используете формат "o" или "O".

Вам нужно будет установить параметр styles в DateTime.ParseExact в DateTimeStyles.RoundtripKind.

Подробнее см. в: http://msdn.microsoft.com/en-us/library/az4se3k1%28v=vs.110%29.aspx#Roundtrip