Используя Датавремя.TryParseExact не зная года

у меня есть метод, который (иногда) принимает строку в формате "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 ответов


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

во-вторых, есть ли какая-то особая причина, по которой вы используете 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).