views:

83

answers:

3

Hallo,

I am working on a Core Data app and have to do some filtering based on dates. I've run some testing and it appears that when comparing NSDates, Core Data is comparing the time component of the dates as well.

My code:

- (BOOL)hasSpeakersWithinDateRangeFrom:(NSDate *)startOfRange through:(NSDate *)endOfRange {
    NSPredicate* dateRangePredicate = [NSPredicate predicateWithFormat:@"startOn <= %@ && endOn >= %@", startOfRange, endOfRange];
    NSSet* speakersWithinDateRange = [self.speakers filteredSetUsingPredicate:dateRangePredicate];

    if ([speakersWithinDateRange count] > 0)
        return YES;
    else
        return NO;
}

and I have a "convenience" method that is a one-line'er:

- (BOOL)hasSpeakersNow {
    return [self hasSpeakersWithinDateRangeFrom:[NSDate date] through:[NSDate date]];
}

When I run some basic testing, it doesn't work as planned, and from what I can tell Core Data is comparing the time components of the NSDate objects along with the dates.

So, how can I rewrite the above to ignore time and only be sensitive to the day passed?

Thank you

+3  A: 

You might want to get familiar with NSDateComponents and NSCalendar. What you will probably need to do is extract the components from your date and construct new NSDates using only the day, month, and year components without time components.

For the "current" day, you'll want to create a 1 day range by using today's date at midnight, and the date by adding 1 day to that. NSCalendar has methods to do some of this for you.

These docs might help:

Jason Foreman
A: 

Set the startDate to time 0:00:00 and the endDate to 23:59:59

NSDate *startDate = [NSDate date]; //Now
startDate= [date dateAtMidnight]; //today at 0:00

NSDate *endDate = [NSDate date];

NSCalendar *cal = [[NSCalendar alloc] initWithCalendarIdentifier:@"gregorian"];
NSDateComponents *comps = [[NSDateComponents alloc] init];
[comps setDay:1];
[comps setSecond:-1]
endDate = [cal dateByAddingComponents:comps toDate:endDate  options:0];//today 23:59:59

edit

this solution uses NSDate-Category NSDateAdditions.h, provided by Three20 (I wasnt aware it isn't defined in Cocoa)

- (NSDate*)dateAtMidnight {
  NSDateFormatter* formatter = [[NSDateFormatter alloc] init];
  formatter.dateFormat = @"yyyy-d-M";

  NSString* formattedTime = [formatter stringFromDate:self];
  NSDate* date = [formatter dateFromString:formattedTime];
  [formatter release];
  return date;
}
vikingosegundo
hm, jason was faster
vikingosegundo
AFAIK, there is no such method `dateAtMidnight` on NSDate.
chrispix
@chrispix: Yeah, u r right. see my edit.
vikingosegundo
The solution provided by Three20 is **TERRIBLE**. Use in `NSDateComponents`.
Marcus S. Zarra
A: 

This is essentially the same as vikingosegundo, but both functions use the same method, and I personally prefer it for my use.

- (NSDate *)dateByMovingToBeginningOfDay
{
  unsigned int flags = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit;
  NSDateComponents* parts = [[NSCalendar currentCalendar] components:flags fromDate:self];
  [parts setHour:0];
  [parts setMinute:0];
  [parts setSecond:0];
  return [[NSCalendar currentCalendar] dateFromComponents:parts];
}

- (NSDate *)dateByMovingToEndOfDay
{
  unsigned int flags = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit;
  NSDateComponents* parts = [[NSCalendar currentCalendar] components:flags fromDate:self];
  [parts setHour:23];
  [parts setMinute:59];
  [parts setSecond:59];
  return [[NSCalendar currentCalendar] dateFromComponents:parts];
}
Jus' Wondrin'