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, если вам все еще нужна проверка формата жесткой строки.