Search code examples
c#datetimeicomparer

Using IComparer to get index where DateTime is greater than


Given:

List<DateTime> descOrderedDates;

And a datetime:

DateTime fromDate;

I can easily count the number of items where the date is greater than fromDate as follows:

var count = descOrderedDates.Count(c=> c > fromDate);

However I'm struggling to implement this as a BinarySearch:

var ix = descOrderedDates.BinarySearch(fromDate, new CompareDates());

private class CompareDates : IComparer<DateTime>
{
    public int Compare(DateTime compareDate, DateTime fromDate)
    {
        if (fromDate > compareDate) return 1;
        return 0;
    }
}

This keeps returning 1 in a test case where fromDate is less than the smallest date in the list. I'm struggling to wrap my head around IComparer, can anyone tell me what I'm doing wrong?


Solution

  • You are supposed to return either a negative value, a positive value, or 0 in Compare, depending on whether the parameters are greater than, less than, or equal to each other, as the documentation says. (So your implementation of not returning negative values at all is incorrect.)

    You can do that by explicitly writing out the three cases and comparing the dates with < and >, but DateTime has the CompareTo method (as it implements IComparable), so you can just use that instead:

    public int Compare(DateTime date1, DateTime date2)
        => date2.CompareTo(date1);
    

    Note that the order of the two dates are reversed when we call CompareTo, to achieve the descending order for the Comparer that we are implementing.

    If you want to find the first index of the list with a date that is less than fromDate, you also need to do some checking on ix:

    int firstIndexLessThanFromDate;
    if (ix < 0) {
        // applying bitwise not gives you where the element should be inserted
        // i.e. the index of the next smallest element
        firstIndexLessThanFromDate = ~ix;
    } else {
        firstIndexLessThanFromDate = ix + 1;
    }