【问题标题】:How do I calculate the number of days, minus Sundays, between two dates in C#?如何计算 C# 中两个日期之间的天数(减去星期日)?
【发布时间】:2009-07-07 17:09:16
【问题描述】:

我正在创建一个图书馆管理系统。

我已经使用时间戳来计算日期差异,并且在日期差异的帮助下我也在计算罚款。

现在这个日期差异包括一周中的所有天。但是对于图书馆申请,罚款应该只收取每周 6 天(周一至周六)的费用。

我做不到。

谁能帮我完成这项任务?

提前致谢!!

【问题讨论】:

    标签: c#


    【解决方案1】:

    本质上,您可以计算原始天数;您需要找到要从该数字中减去的星期日数。您知道每 7 天是一个星期天,因此您可以将原始天数除以 7,然后从原始天数中减去该数字。现在您需要删除一周剩余时间内存在的星期日数;原始天数的 mod 会告诉您剩余的天数。要确定该跨度是否包括星期日,您必须知道第一天是星期几;如果您将星期一定义为 0,星期二定义为 1,星期三定义为 3,等等,那么如果您将跨度开始的星期几的值添加到原始数量的 mod (7)天,如果数字是 6 或更大,则您已经跨越了一个额外的星期日,应该从您的罚款数字中删除 1 天。

    在伪代码中:

    int fine;
    int numdays =  endDay - startDay;
    
    fine = numdays - (numdays / 7);
    
    int dayOfWeek = startDate.DayOfWeek;
    if (dayOfWeek + (numdays % 7) > 6)
    {
       fine = fine - 1;
    }
    

    【讨论】:

    • 感谢您的回复。很好的解释你能通过编码以编程方式表示解释吗?
    【解决方案2】:

    这样就可以了:

    private int DaysLate(DateTime dueDate, DateTime returnDate)
    {
        var ts = returnDate - dueDate;
        int dayCount = 0;
    
        for (int i = 1; i <= ts.Days; i++)
        {
            if (dueDate.AddDays(i).DayOfWeek != DayOfWeek.Sunday)
                dayCount++;
        }
    
        return dayCount;
    }
    

    【讨论】:

    • 利用 TimeSpan / Date 类绝对是 IMO 的必经之路。
    • 迄今为止的最佳答案。但是:一般来说,使用“DateTime.Now”是一种“气味”。例如,您如何对此进行单元测试?可能是星期一和星期二的单元测试结果不同。那么,最好添加一个参数,例如“DateTime returnedDate”并从中减去dueDate。其次,要非常警惕 DateTime.Now。它计算当前日期和时间,同时考虑时区。在夏令时更改前后,每年可能会发生两次奇怪的事情。
    • @Jeremy:好点。我根据您的建议修改了功能。
    • 这个解决方案是 O(n)。 O(1) 解决方案更可取。
    • @Jeremy Stein - 绝对同意。虽然假设迭代的天数可能很小,但如果在成百上千的用户上批量完成,性能影响可能会很大。
    【解决方案3】:

    基于 Jacob Proffitt 的回答,但没有内存列表的开销。由于 DaysBetween 动态生成其日期,因此在生成列表时计算计数:

    int c = DaysBetween(begin, end).Count(d => d.DayOfWeek != DayOfWeek.Sunday);
    
    private IEnumerable<DateTime> DaysBetween(DateTime begin, DateTime end)
    {
        for(var d = begin; d <= end; d.AddDays(1)) yield return d;
    }
    

    当然,如果您不想炫耀 LINQ,您可以简化它并使用一个功能:

    private int DaysBetween(DateTime begin, DateTime end)
    {
        int count = 0;
        for(var d = begin; d <= end; d.AddDays(1)) 
           if(d.DayOfWeek != DayOfWeek.Sunday) count++
        return count;
    }
    

    恕我直言,这两者都比大家最喜欢的(乌鸦的回答)更清晰、更容易理解、调试、故障排除和修改。

    当然,这是一个 O(n) 的解决方案,这意味着相隔的天数越多,计算所需的时间就越长。虽然这对于大多数现实世界的应用程序来说可能没问题,但在某些情况下,您可能更喜欢基于公式的方法,类似于以下内容:

    int q = end.Subtract(begin).Days - (end.Subtract(begin).Days / 7);
    

    【讨论】:

      【解决方案4】:

      对此进行了快速测试,似乎可以满足您的目的:(编辑:为清晰起见添加了一些 cmets 并更正了代码错误)

      private static int CalculateDaysToFine(DateTime dateDue, DateTime dateIn)
              {
                  TimeSpan ts = dateIn - dateDue;
                  int daysToFine = ts.Days - (ts.Days/7); //subtract full weeks (1 Sunday each)
                  if (((int)dateDue.DayOfWeek + (ts.Days%7)) >6) //check to see if the remaining days contain a Sunday
                      daysToFine--;
                  return daysToFine;
              }
      

      【讨论】:

      • 如果我的答案会被否决,至少有人可以给出一个理由吗?想知道为什么这不起作用。
      【解决方案5】:

      这是我的实现。我的目标是使用与 McWafflestix 类似的方法的 O(1) 执行时间。我试图保持它的可读性,最大化 OO 代码并尽可能减少“数学魔法”(并不是说我反对数学……或者魔法)。

      这个想法是确定截止日期和返回日期之间完整的 7 天周数,以及一个“增量”天数来调整它以更正该数字。只要您能保证到期日和退货日期都不在星期日(我认为根据您的描述不会有问题),这将按预期工作。

              static int CalculateFineDays(DateTime due, DateTime returned)
              {
                  TimeSpan ts = returned - due;
                  if (ts < TimeSpan.Zero)
                      return 0;
      int delta = returned.DayOfWeek - due.DayOfWeek; return delta + ts.Subtract(TimeSpan.FromDays(delta)).Days * 6 / 7; }

      编辑:我之前提出了一个解决方案,并在其中发现了一个错误,并且在我处理它时,我将代码缩减为这个。

      【讨论】:

        【解决方案6】:

        我的 Linqy 方法(具有更易于阅读的优点,但在创建结构类型列表时对性能的影响很小):

        private int DaysLate(DateTime dateDue, DateTime dateReturned)
        {
            return getDayList(dateDue, dateReturned).Where(d => d.DayOfWeek != DayOfWeek.Sunday).Count();
        }
        
        private List<DateTime> getDayList(DateTime begin, DateTime end)
        {
            List<DateTime> dates = new List<DateTime>();
            DateTime counter = begin;
            while (counter <= end)
            {
                dates.Add(counter);
                counter = counter.AddDays(1);
            }
            return dates;
        }
        

        【讨论】:

        • 这是所有答案中性能最差的示例。在 O(N2) 中,一个简单的数学运算就足够了。
        • 是的,我更喜欢 zvolkov 的回答。不过,我对否决票并没有太大印象。朋克孩子。
        猜你喜欢
        • 1970-01-01
        • 2013-03-30
        • 2017-06-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-02-26
        相关资源
        最近更新 更多