NSPredicate syntax for DATEADD?

2020-04-08 14:36发布

问题:

is there a way to do a DateAdd or a DateDiff function on an NSPredicate? Thank you, Jose.

回答1:

Actually, there is! It's a roundabout way of doing it, because NSPredicate doesn't support it directly (ie, you can't just + anInterval to an NSDate). Fortunately, you can do it, and luckily for you, I just figured it out about 2 days ago.

To clarify: I'm assuming you're asking for something like: "an object has a date property. I want to see if this date property is some arbitrary interval before/after another date". If that's what you mean, then yes you can do it. If that's not what you mean, then please clarify your question.

Here we go. In this example, we're going to assume the object against which we'll be evaluating this predicate has a property called date that returns an NSDate. We are going to see if this date is at least 1 day before another date. There are a couple different ways we could do this comparison:

date + 1 day is before comparisonDate
date is before comparisonDate - 1 day

I'm going to go with the first approach:

NSDate * comparisonDate = ...; //an arbitrary NSDate object, against which we're going to be doing our comparison
NSTimeInterval interval = 86400; //the number of seconds you want add or subtract.

NSPredicate * p = [NSPredicate predicateWithFormat:@"CAST(CAST(date, 'NSNumber') + %f, 'NSDate') < %@", interval, comparisonDate];

What's going on:

To get this to work, we can CAST() a date object to an NSNumber. This is going to convert the NSDate into an NSNumber which is some number of seconds from a reference point in time (such as 1 Jan 1970 or whatever). To that number we add or subtract our interval, and then cast the new number back to an NSDate. Then we can use a regular comparison operator to compare our new date against our comparison date.

There are a couple different variations on this idea, but they all require casting an NSDate to a number (or casting a number to an NSDate) to get its time interval.

Devious, eh?

edit

If Core Data is complaining about the construct of the predicate, try reversing things:

NSDate * comparisonDate = ...;
NSTimeInterval interval = 86400;

NSPredicate * p = [NSPredicate predicateWithFormat:@"date < CAST(CAST(%@, 'NSNumber') - %f, 'NSDate')", comparisonDate, interval];

edit #2

The thunder that The Reverend stole: http://tumblr.com/xqorqjfrz