Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
196 views
in Technique[技术] by (71.8m points)

asp.net - Compare Dates using LINQ

I have a table, which has columns ItemName, purchaseDate and expiryDate. Essentially what i'm trying to do is write a LINQ query that counts and displays all items that are within 45days or less from their expiry date, comparing them using their purchase date.

So far this is what i've been able to do:

 public string stringExpiry { get; set; }
 public int intExpiry { get; set; }

 intExpiry= _context.GetMyItems.Where(p => p.ExpiryDate <= p.PurchaseDate.AddDays(-45)).Count();
 stringExpiry= _context.GetMyItems.Where(p=> p.ExpiryDate<=p.PurchaseDate.AddDays(-45)).ToList();
question from:https://stackoverflow.com/questions/65917603/compare-dates-using-linq

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Let's make this a little bit more generic, so you can use it as any other LINQ method. After that we can specialize in a method for your class

LINQ is defined using extension methods. If you are not familiar how to create an extension method, read Extension Methods Demystified

For the examples I use the following class. Any class with two DateTime properties will do

class PurchasedProduct
{
    public string Name {get; set;}
    public DateTime PurchaseDate {get; set;}
    public DateTime ExpiryDate {get; set;}
} 

Our goal is a method that does the following:

TimeSpan maxTime = TimeSpan.FromDays(45);
IEnumerable<PurchardProduct> purchasedProducts = ...
IEnumerable<PurchasedProducts> almostExpiredProducts =
    purchasedProducts.WhereAlmostExpired(maxTime);

Here we go!

First a method that says whether a class with two DataTimes is near expiry date:

public static bool IsWithinTimeSpan<T>(this T source,
    Func<T, DateTime> startDateSelector,
    Func<T, DateTime> endDateSelector,
    TimeSpan maxTime)
{
    return startDateSelector(source) - endDateSelector(source) < maxTime;
}

In words: take your source. Use the startDateSelector to extract the startDate; Use the endDateSelector to extract the endDate. Subtract these two DateTimes, and return true if the result is less than maxTime;

Usage:

PurchasedProduct purchasedProduct = new PurchasedProduct {...};
bool productNearExpiryDate = product.IsWithinTimeSpan(maxTime);

Well, if we can do this with one T, we can do this with a sequence of T:

public static IEnumerable<T> WhereWithinTimeSpan<T>(
    this IEnumerable<T> source,
    Func<T, DateTime> startDateSelector,
    Func<T, DateTime> expiryDateSelector,
    TimeSpan maxTime)
{
    return source.Where(t => t.IsWithinTimeSpan(
        startDateSelector, expiryDateSelector, maxTime));
}

Well that was easy, only one line of code!

This looks very much like our goal, only one more function to go to make it like the method you want:

public static IEnumerable<PurchasedProduct> WhereAlmostExpired(
    this IEnumerable<PurchasedProduct> purchasedProducts,
    TimeSpan maxTime)
{
    return purchasedProducts.WhereWithinTimeSpan(
    product => product.PurchaseDate,
    product => product.ExpiryDate,
    maxTime);
}

Again, only one line of code! Of course, if your sequence of items is not IEnumerable<PurchasedProduct>, but for instance IEnumerable<MyClass>, change this one line of code accordingly.

So now we are able to use it for your problem:

TimeSpan maxTime = TimeSpan.FromDays(45);
IEnumerable<MyClass> myObjects = ...
IEnumerable<MyClass> almostExpiredObjects = myObjects.WhereAlmostExpired(maxTime);

Simple comme bonjour!

One final remark: if you are not certain that startTime is smaller then endTime, don't forget to use absolute value before your comparison


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...