.NET: Почему TryParseExact не работает на Hmm и Hmmss? - PullRequest
11 голосов
/ 07 января 2010

Я испытываю метод DateTime.TryParseExact, и я натолкнулся на случай, который я просто не понимаю. У меня есть несколько форматов и несколько предметов для разбора, каждый из которых должен идеально соответствовать одному из форматов:

var formats = new[]
     {
         "%H",
         "HH",
         "Hmm",
         "HHmm",
         "Hmmss",
         "HHmmss",
     };

var subjects = new[]
     {
         "1",
         "12",
         "123",
         "1234",
         "12345",
         "123456",
     };

Затем я пытаюсь разобрать их все и распечатать результаты:

foreach(var subject in subjects)
{
    DateTime result;
    DateTime.TryParseExact(subject, formats, 
        CultureInfo.InvariantCulture, 
        DateTimeStyles.NoCurrentDateDefault,
        out result);

    Console.WriteLine("{0,-6} : {1}", 
        subject,
        result.ToString("T", CultureInfo.InvariantCulture));
}

Я получаю следующее:

1      : 01:00:00
12     : 12:00:00
123    : 00:00:00
1234   : 12:34:00
12345  : 00:00:00
123456 : 12:34:56

И на мой вопрос ... почему он не работает на 123 и 12345? Разве они не должны стать 01:23:00 и 01:23:45? Что мне здесь не хватает? И как я могу заставить его работать так, как я ожидал?


Обновление: Похоже, мы могли бы выяснить, почему это не так. Похоже, что H на самом деле захватывает две цифры и затем оставляет только одну для mm, которая затем потерпит неудачу. Но есть ли у кого-нибудь хорошая идея о том, как я могу изменить этот код, чтобы получить результат, который я ищу?

Еще одно обновление: Думаю, я нашел разумное решение сейчас. Добавил это как ответ. Примет это через 2 дня, если кто-то еще не придумал еще лучше. Спасибо за помощь!

Ответы [ 6 ]

13 голосов
/ 07 января 2010

Хорошо, так что я думаю, что теперь все понял благодаря большему количеству чтения, экспериментов и других полезных ответов здесь. Что происходит, так это то, что H , m и s фактически получают две цифры, когда они могут, даже если цифр недостаточно для остальной части формата , Так, например, с форматом Хмм и цифрами 123 , H будет получено 12 , и будет только 3 осталось. И мм требует двух цифр, поэтому он терпит неудачу. Tadaa .

Итак, мое решение в настоящее время - использовать только следующие три формата:

var formats = new[]
    {
        "%H",
        "Hm",
        "Hms",
    };

Если остальная часть кода из моего вопроса не изменилась, я получу в результате:

1      : 01:00:00
12     : 12:00:00
123    : 12:03:00
1234   : 12:34:00
12345  : 12:34:05
123456 : 12:34:56

Что, на мой взгляд, должно быть разумным и приемлемым:)

3 голосов
/ 07 января 2010

0123 012345

Я предполагаю, что он ищет длину 2/4/6, когда находит строку таких чисел. 123 должен быть AM или PM? 0123 не так однозначно.

2 голосов
/ 07 января 2010

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

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

Как отмечали другие, H является неоднозначным, поскольку подразумевает 10-часовой рабочий день, где HH - 12

.
1 голос
/ 07 января 2010

Цитировать из MSDN Использование единого пользовательского спецификатора формата :

Пользовательская строка формата даты и времени состоит из двух или более символов.Например, если строка формата состоит только из спецификатора h, строка формата интерпретируется как стандартный спецификатор формата даты и времени.Однако в данном конкретном случае возникает исключение, поскольку отсутствует стандартный спецификатор формата даты и времени.

Чтобы использовать один настраиваемый спецификатор формата даты и времени, добавьте пробел до или после спецификатора даты и времени или укажите спецификатор формата процента (%) перед единственным настраиваемым спецификатором даты и времени.Например, строки формата «h» и «% h» интерпретируются как пользовательские строки формата даты и времени, которые отображают час, представленный текущим значением даты и времени.Обратите внимание, что если используется пробел, он появляется в виде литерального символа в строке результата.

Итак, должно ли было быть % H в первом элементе массива formats?

Надеюсь, это поможет, С уважением, Том.

1 голос
/ 07 января 2010

Я могу ошибаться, но я подозреваю, что это может быть связано с неоднозначностью, присущей "H" части вашей строки формата - т.е., учитывая строку "123", вы можете иметь дело с часом "1" (01:00) или час «12» (12:00); и поскольку TryParseExact не знает, что является правильным, он возвращает ложь.

Что касается того, почему метод не дает «лучшего предположения»: я боюсь, что документация не на вашей стороне. Из MSDN документации по DateTime.TryParse (выделено мое):

Когда этот метод возвращает, содержит DateTime значение, эквивалентное дате и время, содержащееся в с , если преобразование выполнено успешно, или DateTime.MinValue если преобразование не удалось . Конверсия не работает, если формат s или параметр null, является пустой строкой или не содержать дату и время соответствуют шаблону, указанному в Формат . Этот параметр передан неинициализированный.

0 голосов
/ 07 января 2010

«123» и «12345» кажутся неоднозначными в отношении метода TryParseExact. «12345» может быть, например, 12:34:50 или 01:23:45. Просто предположение, хотя.

...