iOS: NSPredicate using NSDate to compare

user1107173 picture user1107173 · Jul 2, 2014 · Viewed 11.7k times · Source

I have an NSDate attribute called startDate stored in the persistence store in the following format (picture below).

enter image description here

426174354 = July 04, 2014

I need to create (3) NSFetchRequest using predicates.

For startDate:

  1. fetchRequest1 using predicate(s) need to fetch everything that falls in today's date based on User's device time.
  2. fetchRequest2 using predicate(s) need to fetch everything that's in the past, meaning yesterday and before, based on User's device time.
  3. fetchRequest3 using predicate(s) need to fetch everything that's in the future, meaning starting tomorrow and after, based on User's device time.

Below is the code I have so far:

-(NSMutableArray *)getFetchPredicate:(NSUInteger)fetchRequestType
{
    NSDate *now = [self getcurrentTime:[NSDate date]];
    NSDateFormatter *format = [[NSDateFormatter alloc] init];
    format.dateFormat = @"dd-MM-yyyy";
    format.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
    NSString *stringDate = [format stringFromDate:now];
    NSDate *todaysDate = [format dateFromString:stringDate];
    //today's date is now a date without time. 

    NSMutableArray *subpredicates;

    if (fetchRequestType == 1)
    {
        NSPredicate *subPredToday = [NSPredicate predicateWithFormat:@"startDate == %@ ", todaysDate];
        [subpredicates addObject:subPredToday];
    }
    else if (fetchRequestType == 2)
    {
        NSPredicate *subPredPast = [NSPredicate predicateWithFormat:@"startDate < %@", todaysDate];
        [subpredicates addObject:subPredPast];
    }
    else if (fetchRequestType == 3)
    {
        NSPredicate *subPredFuture = [NSPredicate predicateWithFormat:@"startDate > %@", todaysDate];
        [subpredicates addObject:subPredFuture];
    }
    return subPredicates;
}

-(NSDate *)getcurrentTime:(NSDate*)date
{
    NSDate *sourceDate = date;

    NSTimeZone* sourceTimeZone = [NSTimeZone timeZoneWithAbbreviation:@"GMT"];
    NSTimeZone* destinationTimeZone = [NSTimeZone systemTimeZone];

    NSInteger sourceGMTOffset = [sourceTimeZone secondsFromGMTForDate:sourceDate];
    NSInteger destinationGMTOffset = [destinationTimeZone secondsFromGMTForDate:sourceDate];
    NSTimeInterval interval = destinationGMTOffset - sourceGMTOffset;

    NSDate* deviceDateWithTime = [[NSDate alloc] initWithTimeInterval:interval sinceDate:sourceDate];
    return deviceDateWithTime;
}

The code above is not fetching the right objects from CoreData. I have a feeling my predicates for comparison are incorrect. I'm not sure how to convert the stored time in startDate to just Date format only and apply that in Predicates for comparison. Any suggestions?

Answer

spassas picture spassas · Jul 2, 2014

I think there is something wrong with your notion of todaysDate. AFAIK, NSDate represents an absolute point in time, so your effort to create a "Date" without "Time" seems futile. And also the use of NSDateFormatter to set the dates is shaky.

I think you must create two different NSDate objects: startOfCurrentDay (e.g 00:00:00) and endOfCurrentDay (e.g 23:59:59) and personally I would do it by using an NSCalendar. If you do so, your fetch request predicates will be:

 if (fetchRequestType == 1)
    {
        NSPredicate *subPredToday = [NSPredicate predicateWithFormat:@"(startDate >= %@) AND (startDate <= %@)", startOfCurrentDay, endOfCurrentDay];
    }
    else if (fetchRequestType == 2)
    {
        NSPredicate *subPredPast = [NSPredicate predicateWithFormat:@"startDate < %@", startOfCurrentDay];
    }
    else if (fetchRequestType == 3)
    {
        NSPredicate *subPredFuture = [NSPredicate predicateWithFormat:@"startDate > %@", endOfCurrentDay];
    }