Подтвердить что ты не робот

Рассчитайте количество дней недели между двумя датами в С#

Как я могу получить количество будних дней между двумя заданными датами без повторения только между датами между ними и подсчетом будних дней?

Кажется довольно простым, но я не могу найти убедительного правильного ответа, который выполняется следующим образом:

  • Общее количество должно быть включено, поэтому GetNumberOfWeekdays (новый DateTime (2009,11,30), новый DateTime (2009,12,4)) должен составлять 5, с понедельника по пятницу.
  • Должны допускать прыжки дней
  • НЕ просто перебирает все даты между показом в будние дни.

Я нашел аналогичный вопрос с ответом , который близок, но не подходит

4b9b3361

Ответ 1

Из этого ссылка:

    public static int Weekdays(DateTime dtmStart, DateTime dtmEnd)
    {
        // This function includes the start and end date in the count if they fall on a weekday
        int dowStart = ((int)dtmStart.DayOfWeek == 0 ? 7 : (int)dtmStart.DayOfWeek);
        int dowEnd = ((int)dtmEnd.DayOfWeek == 0 ? 7 : (int)dtmEnd.DayOfWeek);
        TimeSpan tSpan = dtmEnd - dtmStart;
        if (dowStart <= dowEnd)
        {
            return (((tSpan.Days / 7) * 5) + Math.Max((Math.Min((dowEnd + 1), 6) - dowStart), 0));
        }
        return (((tSpan.Days / 7) * 5) + Math.Min((dowEnd + 6) - Math.Min(dowStart, 6), 5));
    }


  [1]: http://www.eggheadcafe.com/community/aspnet/2/44982/how-to-calculate-num-of-w.aspx

Тесты (каждый тест возвращает 5):

    int ndays = Weekdays(new DateTime(2009, 11, 30), new DateTime(2009, 12, 4));
    System.Console.WriteLine(ndays);

    // leap year test
    ndays = Weekdays(new DateTime(2000, 2,27), new DateTime(2000, 3, 5));
    System.Console.WriteLine(ndays);

    // non leap year test
    ndays = Weekdays(new DateTime(2007, 2, 25), new DateTime(2007, 3, 4));
    System.Console.WriteLine(ndays);

Ответ 2

O (1) решение:

// Count days from d0 to d1 inclusive, excluding weekends
public static int countWeekDays(DateTime d0, DateTime d1)
{
    int ndays = 1 + Convert.ToInt32((d1 - d0).TotalDays);
    int nsaturdays = (ndays + Convert.ToInt32(d0.DayOfWeek)) / 7;
    return ndays - 2 * nsaturdays
           - (d0.DayOfWeek == DayOfWeek.Sunday ? 1 : 0)
           + (d1.DayOfWeek == DayOfWeek.Saturday ? 1 : 0);
}

Примеры за январь 2014 года:

    January 2014
Su Mo Tu We Th Fr Sa
          1  2  3  4
 5  6  7  8  9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31

countWeekDays(new DateTime(2014, 1, 1), new DateTime(2014, 1, 1)); // 1
countWeekDays(new DateTime(2014, 1, 1), new DateTime(2014, 1, 2)); // 2
countWeekDays(new DateTime(2014, 1, 1), new DateTime(2014, 1, 3)); // 3
countWeekDays(new DateTime(2014, 1, 1), new DateTime(2014, 1, 4)); // 3
countWeekDays(new DateTime(2014, 1, 1), new DateTime(2014, 1, 5)); // 3
countWeekDays(new DateTime(2014, 1, 1), new DateTime(2014, 1, 6)); // 4

N.B. Входы DateTime должны находиться примерно в одно и то же время суток. Если вы создаете объекты DateTime, основанные исключительно на году, месяце и дне, как в приведенных выше примерах, вы должны быть в порядке. В качестве встречного примера, 12:01 утра с 1 января по 11:59 вечера 2 января охватывает всего 2 дня, но вышеуказанная функция будет считаться 3, если вы используете те времена.

Ответ 3

В ответ на eFloh был дополнительный день, если последний день был субботой или воскресеньем. Это исправит это.

     public static int Weekdays(DateTime dtmStart, DateTime dtmEnd)
    {
        if (dtmStart > dtmEnd)
        {
            DateTime temp = dtmStart;
            dtmStart = dtmEnd;
            dtmEnd = temp;
        }

        /* Move border dates to the monday of the first full week and sunday of the last week */
        DateTime startMonday = dtmStart;
        int startDays = 1;
        while (startMonday.DayOfWeek != DayOfWeek.Monday)
        {
            if (startMonday.DayOfWeek != DayOfWeek.Saturday && startMonday.DayOfWeek != DayOfWeek.Sunday)
            {
                startDays++;
            }
            startMonday = startMonday.AddDays(1);
        }

        DateTime endSunday = dtmEnd;
        int endDays = 0;
        while (endSunday.DayOfWeek != DayOfWeek.Sunday)
        {
            if (endSunday.DayOfWeek != DayOfWeek.Saturday && endSunday.DayOfWeek != DayOfWeek.Sunday)
            {
                endDays++;
            }
            endSunday = endSunday.AddDays(1);
        }

        int weekDays;

        /* calculate weeks between full week border dates and fix the offset created by moving the border dates */
        weekDays = (Math.Max(0, (int)Math.Ceiling((endSunday - startMonday).TotalDays + 1)) / 7 * 5) + startDays - endDays;

        if (dtmEnd.DayOfWeek == DayOfWeek.Saturday || dtmEnd.DayOfWeek == DayOfWeek.Sunday)
        {
            weekDays -= 1;
        }

        return weekDays; 

    }

Ответ 4

Это должно быть лучше, чем решение dcp:

    /// <summary>
    /// Count Weekdays between two dates
    /// </summary>
    /// <param name="dtmStart">first date</param>
    /// <param name="dtmEnd">second date</param>
    /// <returns>weekdays between the two dates, including the start and end day</returns>
    internal static int getWeekdaysBetween(DateTime dtmStart, DateTime dtmEnd)
    {
        if (dtmStart > dtmEnd)
        {
            DateTime temp = dtmStart;
            dtmStart = dtmEnd;
            dtmEnd = temp;
        }

        /* Move border dates to the monday of the first full week and sunday of the last week */
        DateTime startMonday = dtmStart;
        int startDays = 1;
        while (startMonday.DayOfWeek != DayOfWeek.Monday)
        {
            if (startMonday.DayOfWeek != DayOfWeek.Saturday && startMonday.DayOfWeek != DayOfWeek.Sunday)
            {
                startDays++;
            }
            startMonday = startMonday.AddDays(1);
        }

        DateTime endSunday = dtmEnd;
        int endDays = 0;
        while (endSunday.DayOfWeek != DayOfWeek.Sunday)
        {
            if (endSunday.DayOfWeek != DayOfWeek.Saturday && endSunday.DayOfWeek != DayOfWeek.Sunday)
            {
                endDays++;
            }
            endSunday = endSunday.AddDays(1);
        }

        int weekDays;

        /* calculate weeks between full week border dates and fix the offset created by moving the border dates */
        weekDays = (Math.Max(0, (int)Math.Ceiling((endSunday - startMonday).TotalDays + 1)) / 7 * 5) + startDays - endDays;

        return weekDays;
    }

Ответ 5

Мне нужны положительные/отрицательные (не абсолютные значения), так вот как я его решил:

    public static int WeekdayDifference(DateTime StartDate, DateTime EndDate)
    {
        DateTime thisDate = StartDate;
        int weekDays = 0;
        while (thisDate != EndDate)
        {
            if (thisDate.DayOfWeek != DayOfWeek.Saturday && thisDate.DayOfWeek != DayOfWeek.Sunday) { weekDays++; }
            if (EndDate > StartDate) { thisDate = thisDate.AddDays(1); } else { thisDate = thisDate.AddDays(-1); }
        }

        /* Determine if value is positive or negative */
        if (EndDate > StartDate) {
            return weekDays;
        }
        else
        {
            return weekDays * -1;
        }
    }

Ответ 6

  public static List<DateTime> Weekdays(DateTime startDate, DateTime endDate)
  {
      if (startDate > endDate)
      {
          Swap(ref startDate, ref endDate);
      }
      List<DateTime> days = new List<DateTime>();

      var ts = endDate - startDate;
      for (int i = 0; i < ts.TotalDays; i++)
      {
          var cur = startDate.AddDays(i);
          if (cur.DayOfWeek != DayOfWeek.Saturday && cur.DayOfWeek != DayOfWeek.Sunday)
              days.Add(cur);
          //if (startingDate.AddDays(i).DayOfWeek != DayOfWeek.Saturday || startingDate.AddDays(i).DayOfWeek != DayOfWeek.Sunday)
          //yield return startingDate.AddDays(i);
      }
      return days;
  }

И даты свопинга

  private static void Swap(ref DateTime startDate, ref DateTime endDate)
  {
      object a = startDate;
      startDate = endDate;
      endDate = (DateTime)a;
  }

Ответ 7

Утилиты для получения диапазона дат:

public IEnumerable<DateTime> GetDates(DateTime begin, int count)
{
    var first = new DateTime(begin.Year, begin.Month, begin.Day);
    var maxYield = Math.Abs(count);
    for (int i = 0; i < maxYield; i++)
    {
        if(count < 0)
            yield return first - TimeSpan.FromDays(i);
        else
            yield return first + TimeSpan.FromDays(i);      
    }
    yield break;
}

public IEnumerable<DateTime> GetDates(DateTime begin, DateTime end)
{
    var days = (int)Math.Ceiling((end - begin).TotalDays);
    return GetDates(begin, days);
}

Демо-код LINQPad:

var begin = DateTime.Now;
var end = begin + TimeSpan.FromDays(14);

var dates = GetDates(begin, end);
var weekdays = dates.Count(x => x.DayOfWeek != DayOfWeek.Saturday && x.DayOfWeek != DayOfWeek.Sunday);
var mondays = dates.Count(x => x.DayOfWeek == DayOfWeek.Monday);
var firstThursday = dates
    .OrderBy(d => d)
    .FirstOrDefault(d => d.DayOfWeek == DayOfWeek.Thursday);

dates.Dump("Dates in Range");
weekdays.Dump("Count of Weekdays");
mondays.Dump("Count of Mondays");
firstThursday.Dump("First Thursday");

Ответ 8

Здесь функция, которая вычисляет счет DayOfWeek между двумя датами. Будьте осторожны, он вычисляет его включительно (включая начальный день и конечный день в расчете):

private int GetWeekdayCount(DayOfWeek dayOfWeek, DateTime begin, DateTime end)
    {
        if (begin < end)
        {
            var timeSpan = end.Subtract(begin);
            var fullDays = timeSpan.Days;
            var count = fullDays / 7; // количество дней равно как минимум количеству полных недель попавших в диапазон
            var remain = fullDays % 7; // остаток от деления

            // и вычислим попал ли еще один день в те куски недели, что остаются от полной
            if (remain > 0)
            {
                var dowBegin = (int)begin.DayOfWeek;
                var dowEnd = (int)end.DayOfWeek;
                var dowDay = (int)dayOfWeek;
                if (dowBegin < dowEnd)
                {
                    // когда день недели начала меньше дня недели конца, например:
                    //  начало       конец
                    //    \/          \/
                    //    -- -- -- -- --
                    // Вс Пн Вт Ср Чт Пт Сб
                    if (dowDay >= dowBegin && dowDay <= dowEnd)
                        count++;
                }
                else
                {
                    // когда день недели начала больше дня недели конца, например:
                    //   конец      начало
                    //    \/          \/
                    // -- --          -- --
                    // Вс Пн Вт Ср Чт Пт Сб
                    if (dowDay <= dowEnd || dowDay >= dowBegin)
                        count++;
                }
            }
            else if (begin.DayOfWeek == dayOfWeek)
                count++;

            return count;
        }
        return 0;
    }

Вот еще один простой аналог предыдущей функции:

private int GetWeekdayCountStupid(DayOfWeek dayOfWeek, DateTime begin, DateTime end)
    {
        if (begin < end)
        {
            var count = 0;
            var day = begin;
            while (day <= end)
            {
                if (day.DayOfWeek == dayOfWeek)
                    count++;
                day = day.AddDays(1);
            }
            return count;
        }
        return 0;
    }

И тесты для обеих функций:

    [TestMethod()]
    public void TestWeekdayCount()
    {
        var init = new DateTime(2000, 01, 01);
        for (int day = 0; day < 7; day++)
        {
            var dayOfWeek = (DayOfWeek)day;
            for (int shift = 0; shift < 8; shift++)
            {
                for (int i = 0; i < 365; i++)
                {
                    var begin = init.AddDays(shift);
                    var end = init.AddDays(shift + i);
                    var count1 = GetWeekdayCount(dayOfWeek, begin, end);
                    var count2 = GetWeekdayCountStupid(dayOfWeek, begin, end);
                    Assert.AreEqual(count1, count2);
                }
            }
        }
    }

Ответ 9

var dates = new List<DateTime>();

        for (var dt = YourStartDate; dt <= YourEndDate; dt = dt.AddDays(1))
        {

            if (dt.DayOfWeek != DayOfWeek.Sunday && dt.DayOfWeek != DayOfWeek.Saturday)
            { dates.Add(dt); }

        }

в этом коде у вас может быть список, что все дни работы между двумя датами.

если вы хотите, чтобы подсчет этих дат мог получить dates.Count как целое число. или если вы хотите получить каждый день, вы можете присоединиться к списку в строку.