DateTime.TryParseExact работает не так, как ожидалось

Может ли кто-нибудь объяснить, почему следующий фрагмент возвращает true?

В соответствии с документами для Спецификатор пользовательского формата "d" , "Однозначный день отформатирован без начального нуля". Итак, почему TryParseExact терпит неудачу, когда я даю ему однозначный день с начальным нулем?

DateTime x;
return DateTime.TryParseExact
(
    "01/01/2001",
    @"d\/MM\/yyyy",
    null,
    System.Globalization.DateTimeStyles.None,
    out x
);

UPDATE

Я думаю, может быть, я был непонятен изначально. То, что я действительно пытаюсь понять, - это: Почему TryParseExact принимает некоторые значения, которые не соответствуют точно? из всей документации, которую я видел, 'd' соответствия '01' и '1' так же, как если бы "ММ" соответствовал "Марту", ​​а также "03". Проблема здесь заключается не в том, что значения эквивалентны, а в том, что они не соответствуют формату.

Соответствующие фрагменты документации:

Мне кажется совершенно ясно, что "01" имеет ведущее 0 и поэтому точно не соответствует "d".

Ответ 1

Из источника .NET 4 в DateTimeParse.ParseByFormat():

case 'd':
    // Day & Day of week 
    tokenLen = format.GetRepeatCount();
    if (tokenLen <= 2) { 
        // "d" & "dd" 

        if (!ParseDigits(ref str, tokenLen, out tempDay)) { 
            if (!parseInfo.fCustomNumberParser ||
                !parseInfo.parseNumberDelegate(ref str, tokenLen, out tempDay)) {

                result.SetFailure(ParseFailureKind.Format, "Format_BadDateTime", null);
                return (false); 
            }
        } 
        if (!CheckNewValue(ref result.Day, tempDay, ch, ref result)) { 
            return (false);
        }
    }
    else
    {...}

Синтаксические парсы парсеров "d" и "dd" вместе.

Ответ 2

Похоже, что поведение по дизайну, и я думаю, что он работает таким образом, чтобы соответствовать другим параметрам форматирования строк.

Возьмем следующий пример:

//Convert DateTime to string
string dateFormat = "d/MM/yyyy";
string date1 = new DateTime(2008, 10, 5).ToString(dateFormat);
string date2 = new DateTime(2008, 10, 12).ToString(dateFormat);

//Convert back to DateTime
DateTime x1, x2;
DateTime.TryParseExact(date1, dateFormat, null, System.Globalization.DateTimeStyles.None, out x1);
DateTime.TryParseExact(date2, dateFormat, null, System.Globalization.DateTimeStyles.None, out x2);

Console.WriteLine(x1);
Console.WriteLine(x2);

В первой части ToString() выводит двухзначный день на 12 октября, потому что не имеет смысла просто выписывать день с цифрой (и какую цифру он выбрал бы, 1 или 2?). Так как "d" представляет один OR two значный день при преобразовании в строку, он должен работать таким же образом при обращении к DateTime. Если это не так, преобразование обратно в DateTime в TryParseExact в моем примере завершится неудачно, и это определенно не будет ожидаемым поведением.

Я бы сказал, что если вам действительно нужно точно соответствовать формату ad/MM/yyyy, возможно, вы можете использовать регулярное выражение для проверки строки, а затем передать ее через Parse, TryParse или TryParseExact (в зависимости от насколько хорошо ваше регулярное выражение, так как оно должно обрабатывать високосные годы, 30/31 дней и т.д., если вы хотите использовать Parse).

Ответ 3

TryParseExact просто пытается быть гибким в этом случае, я думаю. Но "d" vs "dd" должен и должен работать, как рекламируется, когда вы конвертируете дату в строку, используя спецификатор формата.

Ответ 4

Я бы сказал, что это не сработает, потому что TryParseExact достаточно умен, чтобы знать, что '01' == '1'.

Ответ 5

Поскольку один "d" означает, что ваше значение DateTime будет преобразовано как краткое, насколько это возможно, то есть без начального нуля, если нет необходимости в нем. Я полагаю, что это не должно терпеть неудачу, когда вы переходите из строки в DateTime, потому что основная цель строки формата TryParseExact - помочь преобразовать в DateTime, то есть она служит как подсказка, она не предназначена для проверьте формат строки.

Вы можете использовать RegEx, если вам все еще нужна проверка формата жесткой строки.