Daniel Olsen
Daniel Olsen

Reputation: 1050

DateTime List find last date that before current

I have a list of dates:

var dates = new List<DateTime>
        {
            new DateTime(2016, 01, 01),
            new DateTime(2016, 02, 01),
            new DateTime(2016, 03, 01),
            new DateTime(2016, 04, 01),
            new DateTime(2016, 05, 01)
        };

Now given a certain date, a "StartDate". What is the easiest way to create a list of dates after the startdate, and the last date before?

I.E. - If I supply the date DateTime(2016, 03, 15), I need to return

DateTime(2016, 03, 01),
DateTime(2016, 04, 01),
DateTime(2016, 05, 01)

It could be as simple as finding the last "Active" date and then just using the where from that date. But I'm unsure on how to do this without making it really complicated.

Upvotes: 4

Views: 2916

Answers (3)

Zein Makki
Zein Makki

Reputation: 30022

Without making it complicated and if i understand your requirements correctly. You want all the dates after the StartDate and the last entry before the first matching (If Any). Then I find this the easiest most readable way of doing it:

var results = dates.FindAll(x => x >= StartDate);
int index = dates.FindLastIndex(x => x < StartDate);

// there might be no match, if all the list is resulted
if (index >= 0)
    results.Insert(0, dates[index]);

If you prefer one query style, you can do the below (I find it not readable):

var results = dates.Where(x => x >= StartDate)
                   .Concat(dates.Where(x => x < StartDate)
                                 .OrderByDescending(x => x).Take(1));

Last Alternative if you like fancy ways:

int startIndex = dates.FindLastIndex(x=> x < StartDate);
startIndex = Math.Max(0, startIndex);

var results = dates.Skip(startIndex).ToList();

Upvotes: 1

Eric Linde
Eric Linde

Reputation: 191

var partialResult = dates.Where(x => x >= date).ToList();
partialResult.Add(dates.Where(x => x < date).Max());
IList<DateTime> result = partialResult.OrderBy(x => x).ToList();

Upvotes: 1

Jon Skeet
Jon Skeet

Reputation: 1500185

If your list is already sorted, you can use a binary search:

var index = dates.BinarySearch(start);
// If the precise value isn't found, index will be the bitwise complement
// of the first index *later* than the target, so we need to subtract 1.
// But if there were no values earlier, we should start from 0.
if (index < 0)
{
    index = Math.Max(~index - 1, 0);
}
return dates.Skip(index).ToList();

This assumes the dates are unique. If there are multiple dates the same as start, there's no guarantee that it will find the first one. If that's a concern, you'd need to search backwards until you found the first match.

You haven't specified whether if there's an exact match, you want to include the date before that or not. If you do, you'll need to adjust this code a bit.

Upvotes: 2

Related Questions