需要:DateTime.TryNew(年、月、日)或DateTime.IsValidDate(年、日、月)

本文关键字:DateTime IsValidDate 需要 TryNew | 更新日期: 2023-09-27 18:25:52

标题基本上说明了一切。我从一个遗留数据库中获得三个用户提供的整数(yearmonthday1(我无法更改)。目前,我使用以下代码将这些整数解析为DateTime结构:

try {
    return new DateTime(year, month, day);
} catch (ArgumentException ex) {
    return DateTime.MinValue;
}

有时,这些值并不代表有效日期(是的,用户输入了1999-06-31之类的内容,而不是,遗留应用程序没有验证这一点)。由于在数据验证失败时抛出异常被认为是一种糟糕的做法,所以我更愿意用无异常的代码来代替它。然而,我能找到的唯一解决方案是将整数转换为一个字符串,并将TryParseExact转换为这个字符串,这对我来说似乎更丑陋。我是否错过了一些明显更好的解决方案?


1实际上,它是YYYYMMDD格式的一个整数,但将其转换为年、月和日是微不足道的。。。

需要:DateTime.TryNew(年、月、日)或DateTime.IsValidDate(年、日、月)

没有静态函数IsValidDate(),所以您必须自己编写,第一个简单的实现可能是:

public static bool IsValidDate(int year, int month, int day)
{
    if (year < DateTime.MinValue.Year || year > DateTime.MaxValue.Year)
        return false;
    if (month < 1 || month > 12)
        return false;
    return day > 0 && day <= DateTime.DaysInMonth(year, month);
}

我说这是一个天真的实现,因为(除了参数范围之外)查看日期是否存在的唯一检查是闰年。在实践中,如果您使用的是非公历(即使在用于将日期与儒略历对齐的公历中也会缺少天数),这可能会因为日历问题而失败。

使用日历

对于非公历,这些假设可能会被打破:

  • 1月1日是最小的有效日期。这不是真的。不同的日历有不同的最小日期。这个限制只是DateTime的技术限制,但可能有一个日历(或日历中的时代)具有不同的最小(和最大)日期
  • 一年中的月数小于或等于12。这不是真的,在一些日历中,上限是13,而且并不总是每年都一样
  • 如果一个日期是有效的(根据所有其他规则),那么它就是有效的日期。事实并非如此,一个日历可能有多个时代,并且并非所有日期都有效(甚至可能在时代日期范围内)

管理这种情况的规则非常复杂,很容易忘记一些事情,所以在这种情况下,捕捉异常可能不是一个坏主意。以前验证功能的更好版本可能只提供基本验证,并依赖DateTime来检查其他规则:

public static DateTime? TryNew(int year,
                               int month,
                               int day,
                               Calendar calendar)
{
    if (calendar == null)
        calendar = new GregorianCalendar();
    if (year < calendar.MinSupportedDateTime.Year)
        return null;
    if (year > calendar.MaxSupportedDateTime.Year)
        return null;
    // Note that even with this check we can't assert this is a valid
    // month because one year may be "shared" for two eras moreover here
    // we're assuming current era.
    if (month < 1 || month > calendar.GetMonthsInYear(year))
        return null;
    if (day <= 0 || day > DateTime.DaysInMonth(year, month))
        return null;
    // Now, probably, date is valid but there may still be issues
    // about era and missing days because of calendar changes.
    // For all this checks we rely on DateTime implementation.        
    try
    {
        return new DateTime(year, month, day, calendar);
    }
    catch (ArgumentOutOfRangeException)
    {
        return null;
    }
}

然后,给定这个新函数,您的原始代码应该是:

return TryNew(year, month, day) ?? DateTime.MinValue;

您可以使用DateTime.DaysInMonth来检查日期是否有效。显然,月份必须在(1;12)范围内