DateTime.TryParseExact не работает должным образом - PullRequest
11 голосов
/ 06 мая 2011

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

Согласно документации для Спецификатор пользовательского формата "d" , "День, состоящий из одной цифры, форматируется без начального нуля«.Так почему же не происходит сбой TryParseExact, когда я даю ему день, состоящий из одной цифры, с начальным нулем?

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

ОБНОВЛЕНИЕ

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

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

  • С TryParseExact : Формат представления строки должен точно соответствовать указанному формату.

  • С The d'Спецификатор : День, состоящий из одной цифры, отформатирован без начального нуля.

Мне совершенно очевидно, что в "01" лидирует 0и, следовательно, не совсем соответствует 'd'.

Ответы [ 5 ]

8 голосов
/ 06 мая 2011

Из источника .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" вместе.

3 голосов
/ 06 мая 2011

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

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

//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" представляет один ИЛИ два цифр дней при преобразовании в строку, при преобразовании обратно в DateTime она должна работать аналогичным образом. Если этого не произойдет, преобразование обратно в DateTime в TryParseExact в моем примере завершится неудачей, и это определенно не будет ожидаемым поведением.

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

0 голосов
/ 06 мая 2011

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

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

0 голосов
/ 06 мая 2011

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

0 голосов
/ 06 мая 2011

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

...