Cocoa-Touch: How do I see if two NSDates are in the same day?

IosObjective CMacosCocoa Touch

Ios Problem Overview


I need to know if two NSDate instances are both from the same day.

Is there an easier/better way to do it than getting the NSDateComponents and comparing day/month/year?

Ios Solutions


Solution 1 - Ios

If you are targeting iOS 8 (and OS X 10.9) or later, then Joe's answer is a better solution using a new method in NSCalendar just for this purpose:

-[NSCalendar isDate:inSameDayAsDate:]

For iOS 7 or earlier: NSDateComponents is my preference. How about something like this:

- (BOOL)isSameDayWithDate1:(NSDate*)date1 date2:(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];
}

Solution 2 - Ios

If you are working with iOS 8 you can use -isDate:inSameDayAsDate:.

From NSCalendar.h:

/*
	This API compares the Days of the given dates, reporting them equal if they are in the same Day.
*/
- (BOOL)isDate:(NSDate *)date1 inSameDayAsDate:(NSDate *)date2 NS_AVAILABLE(10_9, 8_0);

Note that for some reason this didn't make it to the official documentation on Apple's developer site. But it is definitely part of the public API.

Solution 3 - Ios

(Note: Look at Joe's answer for a good way to do this on iOS 8+)

I just use a date formatter:

NSDateFormatter *dateComparisonFormatter = [[[NSDateFormatter alloc] init] autorelease];
[dateComparisonFormatter setDateFormat:@"yyyy-MM-dd"];

if( [[dateComparisonFormatter stringFromDate:firstDate] isEqualToString:[dateComparisonFormatter stringFromDate:secondDate]] ) {
    …
}

HTH.

Solution 4 - Ios

In Swift:

NSCalendar.currentCalendar().isDate(yourDate, equalToDate: yourOtherDate, toUnitGranularity: .Day)

It will return true if they are on the same day.

Solution 5 - Ios

I like progrmr's solution, but I would go even further and make a category of NSDate that provides this method. It will make your code slightly more readable, and you won't need to copy and paste the method into each new class that might need it – just import the header file.

#NSDate+SameDay.h

@interface NSDate (SameDay)
- (BOOL)isSameDayAsDate:(NSDate*)otherDate;
@end

#NSDate+SameDay.m

#import "NSDate+SameDay.h"

@implementation NSDate (SameDay)

- (BOOL)isSameDayAsDate:(NSDate*)otherDate {

    // From progrmr's answer...
    NSCalendar* calendar = [NSCalendar currentCalendar];

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

    return [comp1 day]   == [comp2 day] &&
           [comp1 month] == [comp2 month] &&
           [comp1 year]  == [comp2 year];
}

@end

Then, after importing NSDate+SameDay.h in your class, you can use it like so:

if ([myFirstDate isSameDayAsDate:mySecondDate]) {
    // The two dates are on the same day...
}

Solution 6 - Ios

NSDateComponents sounds like the best bet to me. Another tactic to try is toll-free-bridging it to a CFDate, then using CFDateGetAbsoluteTime and doing a subtraction to get the amount of time between the two dates. You'll have to do some additional math to figure out if the time difference lands the dates on the same day, however.

Solution 7 - Ios

I use NSDateComponents to strip out the time aspect and then compare. Something like:

if ([[self beginningOfDay:date1] isEqualToDate:[self beginningOfDay:date2]]) 
{
...
}

- (NSDate *)beginningOfDay:(NSDate *)date {
	NSCalendar *calendar = [NSCalendar currentCalendar];
	
	unsigned unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit |  NSDayCalendarUnit;
	NSDateComponents *comp = [calendar components:unitFlags fromDate:date];
	
	return [calendar dateFromComponents:comp];
}

Solution 8 - Ios

NSCalendar.currentCalendar().isDateInToday(yourNSDate)

Available in iOS 8.0 and later and OS X v10.9 and later.

Solution 9 - Ios

> Is there an easier/better way to do it than getting the NSDateComponents and comparing day/month/year?

Yes, there is an easier way

-[NSCalendar rangeForUnit:startDate:interval:forDate:] This methods makes it easy to set a date to a beginning of a unit (day, hour, month, year,…) and get the length (interval) of that unit.

As a category it might be used like

@interface NSDate (Comparison)
-(BOOL) isSameDay:(NSDate *)rhs;
@end

@implementation NSDate (Comparison)

-(BOOL)isSameDay:(NSDate *)rhs
{
    NSDate *lhs = self;
    NSDate *lhsStart;
    NSDate *rhsStart;
    
    NSCalendar *cal = [NSCalendar currentCalendar];
    [cal rangeOfUnit:NSCalendarUnitDay startDate:&lhsStart interval:NULL forDate:lhs];
    [cal rangeOfUnit:NSCalendarUnitDay startDate:&rhsStart interval:NULL forDate:rhs];
    return [lhsStart compare:rhsStart] == NSOrderedSame;
}

@end

This category should work for all iOS versions and Mac OS X 10.5+.

for iOS 8+ and Mac OS X 10.9+, you can use NSCalendars

- (BOOL)isDate:(NSDate *)date1 equalToDate:(NSDate *)date2 toUnitGranularity:(NSCalendarUnit)unit;

Solution 10 - Ios

in Swift 3.0, iOS8+

if NSCalendar.current.isDate(Date(), equalTo: date, toGranularity: .day) {

}

or

if NSCalendar.current.isDateInToday(date) {
                
}

Solution 11 - Ios

I create my own utility classes.

ZYUtility.h

@interface ZYUtility : NSObject
+ (NSDate *)yesterday;
+ (NSDate *)tomorrow;
+ (NSDate *)endOfDay:(NSDate *)date;
+ (NSDate *)beginningOfDay:(NSDate *)date;
@end

ZYUtility.m

+ (NSDate *)yesterday;
{
	NSCalendar *calendar = [NSCalendar currentCalendar];
	NSDateComponents *componets = [calendar components:NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit
											  fromDate:[NSDate date]];
	componets.day -= 1;
	componets.hour = 24;
	componets.minute = 0;
	componets.second = 0;
	
	return [calendar dateFromComponents:componets];
}

+ (NSDate *)tomorrow;
{
	NSCalendar *calendar = [NSCalendar currentCalendar];
	NSDateComponents *componets = [calendar components:NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit
											  fromDate:[NSDate date]];
	componets.day += 1;
	componets.hour = 0;
	componets.minute = 0;
	componets.second = 0;
	
	return [calendar dateFromComponents:componets];
}

+ (NSDate *)beginningOfDay:(NSDate *)date {
    NSCalendar *calendar = [NSCalendar currentCalendar];

    unsigned unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit |  NSDayCalendarUnit;
    NSDateComponents *comp = [calendar components:unitFlags fromDate:date];

    return [calendar dateFromComponents:comp];
}

+ (NSDate *)endOfDay:(NSDate *)date {
    NSCalendar *calendar = [NSCalendar currentCalendar];

    NSDateComponents *components = [NSDateComponents new];
    components.day = 1;

    NSDate *theDate = [calendar dateByAddingComponents:components
												toDate:[ZYUtility beginningOfDay:date]
											   options:0];

    theDate = [theDate dateByAddingTimeInterval:-1];

    return theDate;
}

Solution 12 - Ios

The following will test whether two dates represent the same day in a given era (which is sufficient in many cases):

- (BOOL)isDate:(NSDate *)date1 sameDayAsDate:(NSDate *)date2 {
    NSCalendar *calendar = [NSCalendar currentCalendar];
	int diff = [calendar ordinalityOfUnit:NSDayCalendarUnit 
                                   inUnit:NSEraCalendarUnit 
                                  forDate:date1] -
			   [calendar ordinalityOfUnit:NSDayCalendarUnit 
                                   inUnit:NSEraCalendarUnit 
                                  forDate:date2];
	return 0 == diff;
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionProdyView Question on Stackoverflow
Solution 1 - IosprogrmrView Answer on Stackoverflow
Solution 2 - IosJoe MasilottiView Answer on Stackoverflow
Solution 3 - IosBen LachmanView Answer on Stackoverflow
Solution 4 - IosvikzillaView Answer on Stackoverflow
Solution 5 - IosaapierceView Answer on Stackoverflow
Solution 6 - IosfbreretoView Answer on Stackoverflow
Solution 7 - IosBruce GeerdesView Answer on Stackoverflow
Solution 8 - IosphilippView Answer on Stackoverflow
Solution 9 - IosvikingosegundoView Answer on Stackoverflow
Solution 10 - IosnorbDEVView Answer on Stackoverflow
Solution 11 - IosZYiOSView Answer on Stackoverflow
Solution 12 - IosWayneView Answer on Stackoverflow