0

I have for example Monday, Thursday and Sunday as draw dates. What would be the way to find the closest dayOfWeek to Datetime.Now with Linq Lambda? I accomplished this with normal function, but I would like to know how to do it with Linq Lambda?

Example of my approach:

    public static DateTime GetSoonestDrawDate(this DateTime from, IEnumerable<LotteryDrawDate> drawDates)
    {

        int hour = 0;
        int minute = 0;

        bool todayDrawOnly = true;

        int difference = 7;
        int tempDifference = 0;

        int todayDay = (int)from.DayOfWeek;
        int drawCutOffDay = 0;

        if (todayDay == 0)
        {
            todayDay = 7;
        }

        var tempCutOffTime = new TimeSpan(23, 59, 59);

        foreach (var drawDate in drawDates)
        {
            // DayId is DayOfWeek
            drawCutOffDay = drawDate.DayId;

            if (drawCutOffDay < todayDay)
            {
                drawCutOffDay += 7;
            }

            tempDifference = drawCutOffDay - todayDay;

            var cutOffTime = new TimeSpan();
            cutOffTime = TimeSpan.Parse(drawDate.CutOffTime);

            if ((difference > tempDifference) || difference == 0)
            {
                // draw date is not today
                if (tempDifference != 0)
                {
                    difference = tempDifference;
                    hour = cutOffTime.Hours;
                    minute = cutOffTime.Minutes;
                    todayDrawOnly = false;
                }
                // same day, cutOffTime still available
                if ((tempDifference == 0 && cutOffTime > from.TimeOfDay))
                {
                    // we use tempCutOffTime to compare newest cutOffTime in case we have more cutOffTimes on the same day
                    // in that case we have to select the soonest cutOffTime of the day
                    if (cutOffTime < tempCutOffTime)
                    {
                        difference = tempDifference;
                        hour = cutOffTime.Hours;
                        minute = cutOffTime.Minutes;
                        todayDrawOnly = true;
                        tempCutOffTime = cutOffTime;
                    }
                }
                // same day selected only, but cutOffTime passed, so we add another week only in case there is only one draw date and draw date is on the same day
                else if (tempDifference == 0 && cutOffTime < from.TimeOfDay && todayDrawOnly == true)
                {
                    if (cutOffTime < tempCutOffTime)
                    {
                        difference = 7;
                        hour = cutOffTime.Hours;
                        minute = cutOffTime.Minutes;
                        todayDrawOnly = true;
                        tempCutOffTime = cutOffTime;
                    }
                }
            }
        }

        from = from.AddDays(difference);

        DateTime soonest = new DateTime(from.Year, from.Month, from.Day, hour, minute, 0);

        return soonest;
    }
Corey Adler
  • 15,897
  • 18
  • 66
  • 80
sensei
  • 7,044
  • 10
  • 57
  • 125
  • Do you mean that you want to know the **next** draw date given a `DateTime`? If today were 11/19 you would want to know the next draw date of 11/21, correct? – IAbstract Nov 18 '13 at 19:29
  • When you say you want it as a lambda, do you mean you want an **expression tree** that can be used with Entity Framework or some other LINQ query provider? Or do you just need a lambda that gets emitted as a delegate? – Mike Strobel Nov 18 '13 at 19:34
  • I think that linq lambda is the best way to avoid mess, or is there any other way to connect this with function with linq lambda? As you can see I am accepting entity list of drawdates as paremeter and doing stuff on it. Would like to know if I can directly somehow use this method on the side I am retrieving drawDates from db(business logic). In that case I would probably have to use lambda linq. – sensei Nov 18 '13 at 20:00

3 Answers3

1

Because you didn't show how LotteryDrawDate looks like, I prepared a little sample using DayOfWeek only. You have to extend that to look at time part by your own.

public static DateTime GetSoonestDrawDate(this DateTime from, IEnumerable<DayOfWeek> drawDates)
{
    var realDrawDates = drawDates.SelectMany(x => new[] { (int)x, (int)x + 7 }).OrderBy(x => x);
    var difference = realDrawDates.SkipWhile(x => x < (int)from.DayOfWeek).First() - (int)from.DayOfWeek;
    return from.AddDays(difference);
}

Little test code:

var drawDates = new[] { DayOfWeek.Monday, DayOfWeek.Wednesday, DayOfWeek.Saturday };

for (int i = 0; i < 15; i++)
{
    var from = DateTime.Now.AddDays(i);
    Console.WriteLine("{0} - {1}", from.ToShortDateString(), GetSoonestDrawDate(from, drawDates).ToShortDateString());
}

prints (from - next):

11/18/2013 - 11/18/2013
11/19/2013 - 11/20/2013
11/20/2013 - 11/20/2013
11/21/2013 - 11/23/2013
11/22/2013 - 11/23/2013
11/23/2013 - 11/23/2013
11/24/2013 - 11/25/2013
11/25/2013 - 11/25/2013
11/26/2013 - 11/27/2013
11/27/2013 - 11/27/2013
11/28/2013 - 11/30/2013
11/29/2013 - 11/30/2013
11/30/2013 - 11/30/2013
12/1/2013 - 12/2/2013
12/2/2013 - 12/2/2013
MarcinJuraszek
  • 124,003
  • 15
  • 196
  • 263
1

A simple method to find the nearest day in the future would be the following:

DayOfWeek[] draw_days = { DayOfWeek.Sunday, DayOfWeek.Monday, DayOfWeek.Thursday };
Console.WriteLine(
  "Nearest Draw Date: {0}",
  draw_days.Min(d => (d <= DateTime.Now.DayOfWeek) ? (d + 7) : d)
);
The Moof
  • 794
  • 4
  • 10
0

If you wanted a simple hardcoded list of draw days, you could do this:

DateTime GetNextDate(DateTime from)
{
    DayOfWeek target;
    switch (from.DayOfWeek)
    {
        case DayOfWeek.Friday:
        case DayOfWeek.Saturday:
        case DayOfWeek.Sunday:
            target = DayOfWeek.Sunday;
            break;
        case DayOfWeek.Monday:
            target = DayOfWeek.Monday;
            break;
        case DayOfWeek.Tuesday:
        case DayOfWeek.Wednesday:
        case DayOfWeek.Thursday:
            target = DayOfWeek.Thursday;
            break;
        default:
            throw new ArgumentException("from");
    }
    while (from.DayOfWeek != target)
        from = from.AddDays(1);
    return from;
}
Tim S.
  • 55,448
  • 7
  • 96
  • 122