Использование DateTime.TryParseExact, не зная года - PullRequest
6 голосов
/ 05 января 2010

У меня есть метод, который (иногда) принимает строку в формате "dddd MMMM dd" (понедельник, январь 04), который необходимо проанализировать в DateTime. Я говорю иногда, потому что это может также быть передано в "Today" или "Tomorrow" в качестве значения.

Код для обработки этого достаточно прост:

if (string.Compare(date, "Today", true) == 0)
    _selectedDate = DateTime.Today;
else if (string.Compare(date, "Tomorrow", true) == 0)
    _selectedDate = DateTime.Today.AddDays(1);
else
    _selectedDate = DateTime.Parse(date);

Это работало до середины декабря. Некоторые из вас, вероятно, уже заметили, что пошло не так.

Это не удалось бы в любую дату в Новом году с ошибкой:

«Строка не была распознана как действительный DateTime, поскольку день недели был неправильным.»

Он был принят "Monday January 04", который является действительной датой 2010 года, но не 2009 года.

Итак, мой вопрос: есть ли способ установить год для текущего или следующего года? Прямо сейчас, как быстрое и грязное исправление, у меня есть это:

if (!DateTime.TryParseExact(date, "dddd MMMM dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out _selectedDate))
    if (!DateTime.TryParseExact(date + " " + (DateTime.Now.Year + 1), "dddd MMMM dd yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out _selectedDate))
        throw new FormatException("That date is not valid.");

Таким образом, он попытается проанализировать его, используя текущий год, и в случае неудачи попытается снова использовать следующий год. Если после этого произойдет сбой, он просто предположит, что это недопустимая дата, потому что мне нужно беспокоиться только за 1 год, но если у кого-то есть более гибкое решение, я был бы признателен. (Обратите внимание, мне не нужно беспокоиться о проверке даты, которая будет передана, она будет действительна как для текущего, так и для следующего года).

1 Ответ

8 голосов
/ 05 января 2010

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

Во-вторых, есть ли какая-то конкретная причина, по которой вы используете String.Compare вместо String.Equals? Я считаю следующее более читабельным:

date.Equals("Today", StringComparison.InvariantCultureIgnoreCase);

Я думаю, что он более четко читает, что происходит (тем более, что нам не нужно помнить, что означает окончательный параметр bool в String.Compare).

Теперь, чтобы понять суть вашего вопроса. Ваш метод прекрасно подходит и очень четко выражает логику. Я бы сделал один небольшой рефакторинг:

public DateTime ParseInThisYearOrNextYear(string s, out DateTime dt)
{
    if (!Parse(s, "dddd MM dd", out dt))
    {
        if (!Parse(s + " " + DateTime.Now.Year + 1, "dddd MM dd yyyy", out dt))
        {
            throw new FormatException();
        }
    }

    return dt;
}

bool Parse(string s, string format, out DateTime dt)
{
    return DateTime.TryParseExact(
        s,
        format,
        CultureInfo.InvariantCulture,
        DateTimeStyles.None,
        out dt
    );
}

Это разделяет ваш метод на две отдельные части функциональности и предотвращает повторение (CultureInfo.InvariantCulture и DateTimeStyles.None), делая тестирование и обслуживание немного проще. (Возможно, вам нужно имя метода лучше, чем Parse; я выбрал короткое, чтобы полоса прокрутки не появлялась в окне кода здесь.)

В качестве последнего предупреждения (не зная деталей вашей системы), вы можете рассмотреть возможность проверки предыдущего года! Просто представьте следующую ситуацию:

  1. Вводится «четверг, 31 декабря» (действительно для 2009 года).
  2. Система переходит границу 1 января в 2010 г.
  3. Код выполняется и проверяет 2010 и 2011 оба из которых не удается.

Просто кое-что рассмотреть в зависимости от природы вашей системы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...