在 C# 中查找下一个日期

Find next occurrence of a date in C#

我想将按月和日标识的日期解析为将来发生的有效 DateTime

假设今天是 2023-05-06,下面是一个 table 的输入和输出值:

Input Output
06-24 2023-06-24
01-05 2024-01-05
02-29 2024-02-29

实现此目的的一种天真的方法是测试对 Year 部分使用 DateTime.Now.Year 是否会产生未来的日期:

var today = DateTime.Now;
bool dateInFuture = new DateTime(today.Year, 02, 29)).CompareTo(today);

但是您可能已经注意到这会导致异常,因为 2023-02-29 不是有效日期。

理想情况下,如果日期实际上无效,我希望这段代码能够计算出来,所以如果 00-46 作为输入传递,它可以告诉我那不是真实的日期,但那是有点棘手,因为我当前的实施因实际有效的日期而失败。

这可能有帮助:

var input = "02-29";
var year = DateTime.Today.Year;
if (DateTime.TryParse($"{year}-{input}", out DateTime date))
{
    var isFutureDate = date > DateTime.Now;
}
else
{
    // TODO: Manage error
}

您可以为此定义一个方法:

public static bool TryGetDate(string input, out DateTime date)
{
    var year = DateTime.Today.Year;

    if (input == "02-29")
    {
        while (!DateTime.IsLeapYear(year))
        {
            year++;
        }
    }

    if (DateTime.TryParse($"{year}-{input}", out date))
    {
        if (date < DateTime.Now)
        {
            date = date.AddYears(1);
        }

        return true;
    }

    return false;
}

并使用它:

var input = "02-29";
if (TryGetDate(input, out DateTime date))
{
    // ...
}
else
{
    // TODO: Manage error
}

您可以使用 DateTime.IsLeapYear(year) - 如 this answer in conjuction with DateTime.TryParse 所示,检查要转换的值是否为有效的日期时间:

您可以在 dotnetfiddle.net 中测试此代码:

DateTime today = DateTime.Now;
Int32 year = DateTime.IsLeapYear(today.Year) ? today.Year : today.AddYears(-2).Year;
DateTime tempDate = DateTime.Now;

// String is concatenated in "yyyy-MM-dd" format: 
if (!DateTime.TryParse(year.ToString() + "-02-29", out tempDate))
{
    // Date is not valid.
    Console.WriteLine("Date (" + year.ToString() + "-02-29" + ") is not valid");
}
else
{
    // Date with "yyyy-MM-dd" format: 
    Console.WriteLine("Date is valid: " + tempDate.ToString("yyyy-MM-dd"));
}

这是我的看法:

DateTime? GetFutureDateFromMonthDay(DateTime today, string monthDay) =>
    Enumerable
        .Range(today.Year, 9)
        .Select(y => DateTime.TryParse($"{y}-{monthDay}", out DateTime result) ? (DateTime?)result : null)
        .Where(x => x != null)
        .Where(x => x > today)
        .FirstOrDefault();

请注意,它向前看 9 年,因为闰年​​之间可能有 8 年的差距,并且您想确保获得未来的日期,因此可能需要再过一年。将 today 更改为 new DateTime(2096, 5, 6) 显示了该问题。

因此,鉴于此输入:

var today = new DateTime(2023, 5, 6);

var data = new[]
{
    new { input = "06-24", output = (DateTime?)new DateTime(2023, 6, 24) },
    new { input = "01-05", output = (DateTime?)new DateTime(2024, 1, 5) },
    new { input = "02-29", output = (DateTime?)new DateTime(2024, 2, 29) },
    new { input = "00-46", output = (DateTime?)null },
};

我运行这个查询:

var query =
    from d in data
    let expected = d.output
    let actual = GetFutureDateFromMonthDay(today, d.input)
    select new
    {
        d.input,
        expected,
        actual,
        check = actual == expected,
    };

我得到这个结果:

如果继续尝试 new DateTime(2096, 5, 6) 我现在明白了:

此代码生成未来日期或 returns null 以指示输入错误。