【问题标题】:Wanted: DateTime.TryNew(year, month, day) or DateTime.IsValidDate(year, month, day)需要:DateTime.TryNew(year,month,day) 或 DateTime.IsValidDate(year,month,day)
【发布时间】:2012-03-17 02:24:00
【问题描述】:

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

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

有时,这些值不代表一个有效的日期(是的,用户输入了 1999-06-31 之类的内容,不,旧版应用程序没有验证这一点)。由于throwing an exception when data validation fails is considered bad practice,我更愿意用无异常代码替换它。但是,我能找到的唯一解决方案是将整数转换为一个字符串和TryParseExact 这个字符串,这对我来说似乎更丑陋。我错过了一些明显更好的解决方案吗?


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

【问题讨论】:

    标签: c# .net validation datetime


    【解决方案1】:

    没有静态函数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;
    

    【讨论】:

    • 应该是month &lt; 1 || month &gt; 12day &gt; 0 &amp;&amp; day &lt;= DateTime.DaysInMonth(year, month)
    • 您的意思可能是month &lt; 1 || month &gt; 12。这不是Java。 ;-)
    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-12-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-15
      • 1970-01-01
      • 2010-09-07
      • 1970-01-01
      相关资源
      最近更新 更多