1

This is my first time comparing dates in Objective-C. I've been searching the web for a while and all the examples I found involve building a NSDate from a string so I decided to ask a new question here... My question is as follows:

I need to know if two NSDates are in the same day, ignoring the time. I got two NSArray's containing a set of dates and one by one I need to determine which one from the first NSArray is in the same day as in the second array.

- (void)setActiveDaysColor:(UIColor *)activeDaysColor
{
    for (DayView *actualDay in _days)
    {
        NSDate *actualDayDate = [actualDay date];

        for (NSDate *activeDayDate in self.dates)
        {
            // Comparison code
            // If both dates are the same, tint actualDay with a different color
        }
    }
}

Thank you in advance and have a nice day.

Alex.

Alex Salom
  • 3,074
  • 4
  • 22
  • 33

5 Answers5

10

create new dates by omitting the time components. and use one of the compare methods

example

NSCalendar *calendar = [NSCalendar currentCalendar];
NSInteger components = (NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit);

NSDateComponents *firstComponents = [calendar components:components fromDate:firstDate];
NSDateComponents *secondComponents = [calendar components:components fromDate:secondDate];

NSDate *date1 = [calendar dateFromComponents:firstComponents];
NSDate *date2 = [calendar dateFromComponents:secondComponents];

NSComparisonResult result = [date1 compare:date2];
if (result == NSOrderedAscending) {
} else if (result == NSOrderedDescending) {
}  else {
}
vikingosegundo
  • 52,040
  • 14
  • 137
  • 178
  • Have a look at [this answer for going to the "beginning of a date"](http://stackoverflow.com/a/1857392/608157) and be a little amazed. – David Rönnqvist May 24 '12 at 09:39
2
-(BOOL)isSameDay:(NSDate*)date1 otherDay:(NSDate*)date2 {
NSCalendar* calendar = [NSCalendar currentCalendar];

unsigned unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit |  NSDayCalendarUnit;
NSDateComponents* comp1 = [calendar components:unitFlags fromDate:date1];
NSDateComponents* comp2 = [calendar components:unitFlags fromDate:date2];

return [comp1 day]   == [comp2 day] &&
[comp1 month] == [comp2 month] &&
[comp1 year]  == [comp2 year];}
raghul
  • 1,008
  • 1
  • 15
  • 33
1

Check NSDate documentation, These are the methods to compare date

  • isEqualToDate
  • earlierDate
  • laterDate
  • compare

in your case

if([actualDayDate isEqualToDate:activeDayDate])
{

}
Ilanchezhian
  • 17,426
  • 1
  • 53
  • 55
suresh
  • 2,365
  • 1
  • 26
  • 36
1

Thanks for all your answers. I found a cleaner answer to my question answered in a totally unrelated post but that actually works perfectly.

if ((unsigned int)[actualDayDate timeIntervalSinceDate:activeDayDate] / 60 / 60 / 24 == 0)
{
     // do Stuff
}
Alex Salom
  • 3,074
  • 4
  • 22
  • 33
  • Note that this code might fail if the user user another calendar than gregorian. comparing of dates must be done within a calendar. http://stackoverflow.com/questions/6184824/core-data-under-japanese-calendar-incorrectly-comparing-dates – vikingosegundo May 24 '12 at 08:52
  • 1
    you better use my solution. if you feel, like it is too many lines of code, create a category on NSDate of it with the method `compareDateOmmitingTime:` – vikingosegundo May 24 '12 at 09:16
1

Instead of the loops that you have in your code you could use a predicate to filter out all the objects that are today. Filtering out what dates are today is done by comparing it to the beginning of today and the end of today.

You can set any NSDate to the beginning of that date like this (see this answer)

NSDate *beginDate = [NSDate date];
[[NSCalendar currentCalendar] rangeOfUnit:NSDayCalendarUnit startDate:&beginDate interval:NULL forDate:beginDate];

Then to get the end date you simply add one day to it. Don't add days by calculating the number of seconds. This won't work with daylight savings! Do it like this (also see this answer):

NSDateComponents *oneDay = [[NSDateComponents alloc] init];
[oneDay setDay:1];
// one day after begin date
NSDate *endDate = [[NSCalendar currentCalendar] dateByAddingComponents:oneDay toDate:beginDate options:0];

Now that you have the two dates that define the range for today you can filter all your DayViews using a NSPredicate to get a new array of all the DayViews who's day is today, like this (see this answer):

// filter DayViews to only include those where the day is today
NSArray *daysThatAreToday = [_days filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"(date >= %@) AND (date <= %@)", beginDate, endDate]];

Now you can apply the tint color to all the DayViews by enumerating the new array (that contains todays DayViews)

[daysThatAreToday enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
    // Set the tint color here...
}];

This, in my opinion, is a clean but more importantly a correct way of solving your problem. It reads clearly and handles daylight savings and other calendars then gregorian. It can also easily be reused if you want to tint all the DayViews for a certain week (or any other time period).

Community
  • 1
  • 1
David Rönnqvist
  • 56,267
  • 18
  • 167
  • 205
  • 1
    note, that with this code, you will remove your time components entirely. if you still need it, you should do `NSDate *newStartDateDay = nil; [[NSCalendar currentCalendar] rangeOfUnit:NSDayCalendarUnit startDate:&newStartDateDay interval:NULL forDate:actualDate];` and compare newStartDate, but use beginDate. – vikingosegundo May 24 '12 at 13:14
  • That is why I created two new variables for `beginDate` and `endDate` that is used for sorting. Your point is still valid, these variables **will be have their time components removed** – David Rönnqvist May 24 '12 at 13:17
  • I just wanted to point that out — not that it leads to confusion, when suddenly all events starts at 00:00. – vikingosegundo May 24 '12 at 13:18
  • Its good to point out. Though I never modify the dates that I'm filtering so that shouldn't happen – David Rönnqvist May 24 '12 at 13:22