23

I have a list of objects and each object has a ExpirationDate property which is of type DateTime. I want to retrieve the latest date in the list. Is there an elegant way of doing that through LINQ?

Something like:

DateTime latestDate =  myCollection.Where(r=>r.ExpirationDate.HasValue).MaxDate(r=>r.ExpirationDate.Value);
3
  • What is the behaviour you want if the collection is empty or if there are no items with an ExpirationDate set?
    – Bob Vale
    Commented Jul 21, 2011 at 12:16
  • @BobVale if ExpirationDate is of Type DateTime every r will have an ExpirationDate. As DateTime is a struct, ExpirationDate can never be null.
    – Offler
    Commented Feb 6, 2014 at 14:02
  • @Offler But if you look, the OP uses ExpirationDate.HasValue and ExpirationDate.Value indicating that ExpirationDate is of type DateTime? (ie Nullable<DateTime>)
    – Bob Vale
    Commented Feb 6, 2014 at 14:19

4 Answers 4

39
DateTime? latestDate = myCollection.Max(r => r.ExpirationDate);

Intellisense should have given you the Max() method. =)


Now, if you must assign it to a DateTime, I would consider doing thus:

DateTime latestDate = myCollection.Where(r => r.ExpirationDate.HasValue)
                                  .Max(r => r.ExpirationDate)
                                  .Value;

This will not cover the case of an empty collection or a collection with only null ExpirationDates.


Depending on your earlier logic, checking

myCollection.Any(r => r.ExpirationDate.HasValue)

might be a good idea before trying to assign a value.

7
  • Heh, it did look right to me too, but where's the MaxDate()? :)
    – Gleno
    Commented Jul 21, 2011 at 11:10
  • The where condition is unecessary, also Type will be DateTime? not DateTime so this code will error.
    – Bob Vale
    Commented Jul 21, 2011 at 11:14
  • The where condition was removed earlier - missed the DateTime?. =)
    – J. Steen
    Commented Jul 21, 2011 at 11:15
  • @J. Steen - i want to return a DateTime (not a DateTime?)
    – leora
    Commented Jul 21, 2011 at 11:28
  • 1
    @ooo - its not just empty collection, its also if none of your values have an expiration date.
    – Bob Vale
    Commented Jul 21, 2011 at 12:24
8

You are almost there. Use Max:

DateTime? biggest = myCollection.Max(r=>r.ExpirationDate);

If all expiration dates are null or the collection is empty you will get Null as a result, otherwise the greatest date.

As you have commented on J. Sheens' answer that you want an DateTime as a result you will need to do something about any empty collection or no items with a value, you could do this with

DateTime biggest=myCollection.Max(r=>r.ExpirationDate) ?? DateTime.MinValue

This will give you DateTime.MinValue instead of nulls in my previous example (it also has the advantage over using the any clause that it iterates the collection once). I picked MinValue as an example. You could use your own abitary date.

Using the DateTime? is better, because it allows you to use null for what it's meant to mean - undefined as MinValue could be a valid item in your list.

0
3

Just make sure there is a NullReference check before assigning .ExpriationDate:

DateTime maxDate = myCollection.OrderByDescending(o => o.ExpirationDate).Take(1).FirstOrDefault().ExpirationDate;

Bob Vale had the right idea with

DateTime maxDate = objL.Max(o => o.ExpirationDate);
6
  • 1
    Is the Take(1) necessary as you have FirstOrDefault()?
    – Bob Vale
    Commented Jul 21, 2011 at 11:21
  • No. You can't ever get a null reference exception on a DateTime. DateTime is a value type, which means it resides on the stack. NullReferenceException is for reference types (on the heap). See code: DateTime dt; Console.WriteLine(dt.ToShortDateString());. Nullable<DateTime> works the same way.
    – mattmc3
    Commented Jul 21, 2011 at 11:45
  • @mattmc3 - But the type would not be a DateTime, the type would be the surrounding class, The poster was indicating that FirstOrDefault could return null, so you would get a null reference exception when you accessed the ExpirationDate property on the end
    – Bob Vale
    Commented Jul 21, 2011 at 12:36
  • Matt the null exception does throw if you try to access a property on the .First() if the collection is empty..its' not on DateTime that it is throw but on the object containing the datetime.
    – Ryan Fisch
    Commented Jul 21, 2011 at 12:44
  • Bob, no you are correct...I was rushing out door this morning and shoudl have slowed down...Take(1) is not required if you use First or FirstOrDefault()
    – Ryan Fisch
    Commented Jul 21, 2011 at 12:45
-1

Sort the list by the date descending and take the first (projecting if necessary).

var latestExpirationDate = myCollection
    .Where(item => item.ExpirationDate.HasValue)
    .OrderByDescending(item => item.ExpirationDate)
    .Select(item => item.ExpirationDate) // DateTime?
    .FirstOrDefault();
if (latestExpirationDate != null)
{
    // do something with the value stored in latestExpirationDate
}

As I wrote this, I was under the impression that the Max() method only operated on numeric types (i.e., int, short, decimal, etc.). It appears to work with DateTime objects too. So this could work as well:

var expiredItems = myCollection
    .Where(item => item.ExpirationDate.HasValue);
if (expiredItems.Any())
{
    var latestExpirationDate = expiredItems.Max(item => item.ExpirationDate.Value);
    // do something with latestExpirationDate
}
10
  • Not necessary since it was projected to the date first. Commented Jul 21, 2011 at 11:17
  • 1
    First() will throws an exception with an empty collection
    – Bob Vale
    Commented Jul 21, 2011 at 11:19
  • Ok so what? Big deal. That was not a constraint in the question and therefore not a concern for us. Commented Jul 21, 2011 at 11:24
  • Max() operates on IComparables. =)
    – J. Steen
    Commented Jul 21, 2011 at 11:25
  • 1
    @J.Steen: Which I had realized after trying to verify the solutions that used Max(). :) Commented Jul 21, 2011 at 11:27

Not the answer you're looking for? Browse other questions tagged or ask your own question.