简体   繁体   English

在不知道年份的情况下使用DateTime.TryParseExact

[英]Using DateTime.TryParseExact without knowing the year

I have a method that (sometimes) takes in a string in the format "dddd MMMM dd" (Monday January 04) that needs to get parsed into a DateTime. 我有一个方法(有时)采用格式为"dddd MMMM dd" (04年1月1日星期一)的字符串,需要将其解析为DateTime。 I say sometimes because it may also get passed in "Today" or "Tomorrow" as the value. 我有时说,因为它也可以在"Today""Tomorrow"作为价值传递。

The code to handle this was simple enough: 处理这个的代码很简单:

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);

This worked until halfway through December. 这一直持续到12月中旬。 Some of you have probably already spotted what went wrong. 你们中的一些人可能已经发现了什么问题。

This would have failed on any date in the New Year with the error: 这将在新年的任何日期失败并出现错误:

"String was not recognized as a valid DateTime because the day of week was incorrect." “字符串未被识别为有效的DateTime,因为星期几不正确。”

It was getting passed "Monday January 04" which is a valid date for 2010, but not in 2009. 它正在通过"Monday January 04" 2010年"Monday January 04" ,这是2010年的有效日期,但不是在2009年。

So my question is: Is there any way to set the year either for the current year or the next year? 所以我的问题是:有没有办法设定当年或明年的年份? Right now, as a quick and dirty fix, I have this: 现在,作为一个快速和肮脏的修复,我有这个:

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.");

So it will try to parse it using the current year, and if it is unsuccessful it will try again using the next year. 所以它将尝试使用当前年份解析它,如果它不成功,它将在下一年再次尝试。 If it fails after that, it'll just assume it's an invalid date because I only need to worry about 1 year in advance, but if anyone has a more flexible solution, I'd appreciate it. 如果它在那之后失败,它只会假设它是一个无效的日期,因为我只需要提前1年担心,但如果有人有更灵活的解决方案,我会很感激。 (Note, I don't need to worry about validating the date that gets passed in, it will be valid for either the current or following year). (注意,我不需要担心验证传入的日期,它对当前或下一年有效)。

First, your unit testing should have caught this. 首先,你的单元测试应该抓住这个。 You might want to revisit the tests that you wrote for this method to learn from this experience on how to cover your functionality more throughly. 您可能希望重新访问为此方法编写的测试,以便从这种经验中学习如何更全面地覆盖您的功能。

Second, is there any particular reason why you are using String.Compare instead of String.Equals ? 第二,你是否有任何特殊原因使用String.Compare而不是String.Equals I consider the following more readable: 我认为以下更具可读性:

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

I think it more clearly reads what is happening (especially as we don't have to remember what the final bool parameter means in String.Compare ). 我认为它更清楚地读取正在发生的事情(特别是因为我们不必记住最终的bool参数在String.Compare中的String.Compare )。

Now, to get the heart of your question. 现在,来了解你的问题的核心。 Your method is perfectly fine and very clearly expresses the logic. 你的方法非常好,非常清楚地表达了逻辑。 I would make one small refactoring however: 不过我会做一个小的重构:

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
    );
}

This separates your method into two distinct pieces of functionality and prevents from repeating yourself ( CultureInfo.InvariantCulture and DateTimeStyles.None ) making testing and maintenance a little easier. 这将您的方法分成两个不同的功能部分,并防止重复自己( CultureInfo.InvariantCultureDateTimeStyles.None )使测试和维护更容易一些。 (You probably want a better method name than Parse ; I chose a short one to prevent the scroll bar from appearing in the code window here.) (你可能想要一个比Parse更好的方法名;我选择了一个短的方法来防止滚动条出现在这里的代码窗口中。)

As one last caveat (without knowing the details of your system) you might want to consider also checking the prior year! 作为最后一个警告(不知道您的系统的详细信息),您可能还要考虑检查前一年! Just imagine the following situation: 想象一下以下情况:

  1. Input is "Thursday December 31" (valid for 2009). 输入是“12月31日星期四”(2009年有效)。
  2. System rolls over January 1 boundary into 2010. 系统将1月1日的边界滚动到2010年。
  3. Code is executed and checks 2010 and 2011 both of which fail. 执行代码并检查2010年和2011年两者都失败。

Just something to consider depending on the nature of your system. 根据系统的性质,可以考虑一些事项。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM