Search code examples
iosobjective-cswiftnsdatenspredicate

NSPredicate with NSDate filtering by day/month but not year


I need to create a predicate which needs to filter a list of objects using the property creationDate which is a NSDate object. I want to obtain the list of objects that have the same day and month, but not the same year. Practically, I want the objects that occurred today (as day/month) in the past. How can I create this predicate? For example : today is July 27th 2016 and I want all the objects that have July 27th as creationDate.


Solution

  • First, to extract a day and month from a date...

    NSDateComponents *components = [[NSCalendar currentCalendar] components:NSCalendarUnitDay | NSCalendarUnitMonth | NSCalendarUnitYear fromDate:date];
    NSInteger day = [components day];
    NSInteger month = [components month];
    

    Next, (one way) to build a predicate...

    [NSPredicate predicateWithBlock:^BOOL(id object, NSDictionary * bindings) {
        // object must be cast to the type of object in the list
        MyObject *myObject = (MyObject *)object;
        NSDate *creationDate = myObject.creationDate;
    
        // do whatever you want here, but this block must return a BOOL
    }];
    

    Putting those ideas together...

    - (NSPredicate *)predicateMatchingYearAndMonthInDate:(NSDate *)date {
        NSDateComponents *components = [[NSCalendar currentCalendar] components:NSCalendarUnitDay | NSCalendarUnitMonth | NSCalendarUnitYear fromDate:date];
        NSInteger day = [components day];
        NSInteger month = [components month];
    
        return [NSPredicate predicateWithBlock:^BOOL(id object, NSDictionary * bindings) {
            MyObject *myObject = (MyObject *)object;
            NSDate *creationDate = myObject.creationDate;
            NSDateComponents *creationComponents = [[NSCalendar currentCalendar] components:NSCalendarUnitDay | NSCalendarUnitMonth | NSCalendarUnitYear fromDate:creationDate];
            NSInteger creationDay = [creationComponents day];
            NSInteger creationMonth = [creationComponents month];
            return day == creationDay && month == creationMonth;
        }];
    }
    

    That's it. Build the predicate with some NSDate who's day and month you want to match in the array, then run that predicate on the array (filteredArrayUsingPredicate:).

    NSDate *today = [NSDate date];
    NSPredicate *predicate = [self predicateMatchingYearAndMonthInDate:today];
    NSArray *objectsCreatedToday = [myArray filteredArrayUsingPredicate:predicate];