1

I have a list of DayOfWeek enum item: var daysOfWeek = List<DayOfWeek>

This list contains a variable amount of DaysOfWeek items, e.g. Monday, Thursday, Saturday.

I would like to find the next DateTime to any given DateTime based on List<DayOfWeek>.

If the given date would fall on a Wednesday, the next DateTime which should return would be a Thursday.

If the given date would fall on a Thursday, the next DateTime which should return would be a Saturday.

So far, I have been fiddling around with the some LINQ expressions and trying some options with the Min() extension method but have no code which I could share that would be workable. I am wondering if I am missing some real basic LINQ functionality.

SO-Topics that have given me some ideas so far include this one and that one, however I was not able to produce a solution for my problem with their answers.

Scott Hannen
  • 27,588
  • 3
  • 45
  • 62
jrn
  • 2,640
  • 4
  • 29
  • 51

4 Answers4

3
public static DateTime GetNextDateOrSomething(DateTime start, IEnumerable<DayOfWeek> weekdays)
{
    if (!weekdays.Any()) throw new ArgumentException($"{nameof(weekdays)} cannot be empty.");
    var increments = Enumerable.Range(1, 6);
    var matchedIncrement = increments.FirstOrDefault(i => weekdays.Contains(start.AddDays(i).DayOfWeek));
    return start.AddDays(matchedIncrement > 0 ? matchedIncrement : 7);
}

[DataTestMethod]
[DataRow("4/10/2019", "Wednesday,Thursday", "4/11/2019")]
[DataRow("4/10/2019", "Thursday", "4/11/2019")]
[DataRow("4/10/2019", "Monday,Tuesday", "4/15/2019")]
[DataRow("4/10/2019", "Tuesday", "4/16/2019")]
public void TestDateMethod(string start, string weekdays, string expected)
{
    var startDate = DateTime.Parse(start);
    var weekDaysList = weekdays.Split(',').Select(d => (DayOfWeek)Enum.Parse(typeof(DayOfWeek), d));
    var expectedDate = DateTime.Parse(expected);
    var result = GetNextDateOrSomething(startDate, weekDaysList);
    Assert.AreEqual(expectedDate, result);
}
Scott Hannen
  • 27,588
  • 3
  • 45
  • 62
1

You can compute the (non-negative) distance between tomorrow and the next day of week in the list, then use the minimum distance to get the new date:

var tomorrowDOW = startDate.AddDays(1).DayOfWeek;
var dist = daysOfWeek.Select(w => (w - tomorrowDOW + 14) % 7).Min();
var nextDate = startDate.AddDays(dist + 1);
NetMage
  • 26,163
  • 3
  • 34
  • 55
1
class Program
    {
        static DateTime NextDay(List<DayOfWeek> workingDays, DateTime dateTime)
        {
            var result = dateTime;
            var dayOfWeek = (int)dateTime.DayOfWeek;

            dayOfWeek++;
            result = result.AddDays(1);

            while (!workingDays.Any(x=> x == (DayOfWeek)dayOfWeek))
            {
                if (dayOfWeek > (int)workingDays.Last())
                {
                    var delta = ((int)workingDays.First() + 7) - dayOfWeek;
                    dayOfWeek = (int)workingDays.First();
                    result = result.AddDays(delta);

                }
                else
                {
                    dayOfWeek++;
                    result = result.AddDays(1);
                }
            }
            return result;
        }

        static void Main(string[] args)
        {
            var workingDays = new List<DayOfWeek>()
            {
                DayOfWeek.Monday,
                DayOfWeek.Thursday,
                DayOfWeek.Saturday
            };

            workingDays.Sort();

            var dayOfWeek = NextDay(workingDays, DateTime.Now);
            Console.WriteLine(dayOfWeek.ToString());

            dayOfWeek = NextDay(workingDays, DateTime.Now.AddDays(1));
            Console.WriteLine(dayOfWeek.ToString());

            dayOfWeek = NextDay(workingDays, DateTime.Now.AddDays(2));
            Console.WriteLine(dayOfWeek.ToString());

            dayOfWeek = NextDay(workingDays, DateTime.Now.AddDays(3));
            Console.WriteLine(dayOfWeek.ToString());

            Console.ReadLine();
        }
    }
}
1

Besides the great answers posted for this question, here is another solution which worked great for me. I created the following private method to return the next DateTime based on a given DateTime for a List of valid DayOfWeek items:

private static DateTime NextDateTimeByDayOfWeek(DateTime target, List<DayOfWeek> validDaysOfWeek)
    {
        return Enumerable.Range(1, 7)
            .Select(n => target.AddDays(n))
            .First(date => validDaysOfWeek.Contains(date.DayOfWeek));
    }
jrn
  • 2,640
  • 4
  • 29
  • 51