Get DateTime of the next nth day of the month

后端 未结 4 1391
慢半拍i
慢半拍i 2021-01-20 03:22

If given a date and a variable n, how can I calculate the DateTime for which the day of the month will be the nth Date?

For example, Today is the 17th of June. I wou

相关标签:
4条回答
  • 2021-01-20 03:27

    Why not just do?

    private DateTime GetNextDate(DateTime dt, int DesiredDay)
    {
        if (DesiredDay >= 1 && DesiredDay <= 31)
        {
            do
            {
                dt = dt.AddDays(1);
            } while (dt.Day != DesiredDay);
            return dt.Date;
        }
        else
        {
            throw new ArgumentOutOfRangeException();
        }     
    }
    
    0 讨论(0)
  • 2021-01-20 03:31

    The spec is a little bit unclear about to do when today is the dayOfMonth. I assumed it was it to return the same. Otherwise it would just be to change to <= today.Day

    public DateTime FindNextDate(int dayOfMonth, DateTime today)
    {
        var nextMonth = new DateTime(today.Year, today.Month, 1).AddMonths(1);
        if(dayOfMonth < today.Day){ 
          nextMonth = nextMonth.AddMonths(1);
        }
        while(nextMonth.AddDays(-1).Day < dayOfMonth){
           nextMonth = nextMonth.AddMonths(1);
        }
        var month = nextMonth.AddMonths(-1);
        return new DateTime(month.Year, month.Month, dayOfMonth);
    
    }
    
    0 讨论(0)
  • 2021-01-20 03:37

    Fun little puzzle. I generated 100 DateTimes which represent the starting day of each month, then checked each month to see if it had the date we want. It's lazy so we stop when we find a good one.

    public DateTime FindNextDate(int dayOfMonth, DateTime today)
    {
      DateTime yesterday = today.AddDays(-1);
      DateTime currentMonthStart = new DateTime(today.Year, today.Month, 1);
      var query = Enumerable.Range(0, 100)
        .Select(i => currentMonthStart.AddMonths(i))
        .Select(monthStart => MakeDateOrDefault(
          monthStart.Year, monthStart.Month, dayOfMonth,
          yesterday)
        .Where(date => today <= date)
        .Take(1);
    
      List<DateTime> results = query.ToList();
      if (!results.Any())
      {
        throw new ArgumentOutOfRangeException(nameof(dayOfMonth))
      }
      return results.Single();
    }
    
    public DateTime MakeDateOrDefault(
      int year, int month, int dayOfMonth,
      DateTime defaultDate)
    {
      try
      {
        return new DateTime(year, month, dayOfMonth);
      }
      catch
      {
        return defaultDate;
      }
    }
    
    0 讨论(0)
  • 2021-01-20 03:47

    After many, many edits, corrections and re-writes, here is my final answer:

    The method that follows returns a a DateTime representing the next time the day of number day comes up in the calendar. It does so using an iterative approach, and is written in the form of an extension method for DateTime objects, and thus isn't bound to today's date but will work with any date.

    The code executes the following steps to get the desired result:

    1. Ensure that the day number provided is valid (greater than zero and smaller than 32).
    2. Enter into a while loop that keeps going forever (until we break).
    3. Check if cDate's month works (the day must not have passed, and the month must have enough days in it).
      • If so, return.
      • If not, increase the month by one, set the day to one, set includeToday to true so that the first day of the new month is included, and execute the loop again.

    The code:

    static DateTime GetNextDate3(this DateTime cDate, int day, bool includeToday = false)
    {
        // Make sure provided day is valid
        if (day > 0 && day <= 31)
        {
            while (true)
            {
                // See if day has passed in current month or is not contained in it at all
                if ((includeToday && day > cDate.Day || (includeToday && day >= cDate.Day)) && day <= DateTime.DaysInMonth(cDate.Year, cDate.Month))
                {
                    // If so, break and return
                    break;
                }
    
                // Advance month by one and set day to one
                // FIXED BUG HERE (note the order of the two calls)
                cDate = cDate.AddDays(1 - cDate.Day).AddMonths(1);
    
                // Set includeToday to true so that the first of every month is taken into account
                includeToday = true;
            }
            // Return if the cDate's month contains day and it hasn't passed
            return new DateTime(cDate.Year, cDate.Month, day);
        }
    
        // Day provided wasn't a valid one
        throw new ArgumentOutOfRangeException("day", "Day isn't valid");
    }
    
    0 讨论(0)
提交回复
热议问题