How to determine if an NSDate is today?

IosObjective CCocoa TouchNsdateNscalendar

Ios Problem Overview


How to check if an NSDate belongs to today?

I used to check it using first 10 characters from [aDate description]. [[aDate description] substringToIndex:10] returns string like "YYYY-MM-DD" so I compared the string with the string returned by [[[NSDate date] description] substringToIndex:10].

Is there more fast and/or neat way to check?

Thanks.

Ios Solutions


Solution 1 - Ios

In macOS 10.9+ & iOS 8+, there's a method on NSCalendar/Calendar that does exactly this!

- (BOOL)isDateInToday:(NSDate *)date 

So you'd simply do

Objective-C:

BOOL today = [[NSCalendar currentCalendar] isDateInToday:date];

Swift 3:

let today = Calendar.current.isDateInToday(date)

Solution 2 - Ios

You can compare date components:

NSDateComponents *otherDay = [[NSCalendar currentCalendar] components:NSCalendarUnitEra | NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay fromDate:aDate];
NSDateComponents *today = [[NSCalendar currentCalendar] components:NSCalendarUnitEra | NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay fromDate:[NSDate date]];
if([today day] == [otherDay day] &&
   [today month] == [otherDay month] &&
   [today year] == [otherDay year] &&
   [today era] == [otherDay era]) {
    //do stuff
}

Edit:

I like stefan's method more, I think it makes for a cleaner and more understandable if statement:

NSCalendar *cal = [NSCalendar currentCalendar];
NSDateComponents *components = [cal components:(NSCalendarUnitEra | NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay) fromDate:[NSDate date]];
NSDate *today = [cal dateFromComponents:components];
components = [cal components:(NSCalendarUnitEra | NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay) fromDate:aDate];
NSDate *otherDate = [cal dateFromComponents:components];

if([today isEqualToDate:otherDate]) {
	//do stuff
}

Chris, I've incorporated your suggestion. I had to look up what era was, so for anyone else who doesn't know, it distinguishes between BC and AD. This is probably unnecessary for most people, but it's easy to check and adds some certainty, so I've included it. If you're going for speed, this probably isn't a good method anyway.


NOTE as with many answers on SO, after 7 years this is totally out of date. In Swift now just use .isDateInToday

Solution 3 - Ios

This is an offshoot to your question, but if you want to print an NSDate with "Today" or "Yesterday", use the function

- (void)setDoesRelativeDateFormatting:(BOOL)b

for NSDateFormatter

Solution 4 - Ios

I would try to get today's date normalized to midnight and the second date, normalize to midnight then compare if it is the same NSDate.

From an Apple example here's how you normalize to midnight today's date, do the same for the second date and compare:

NSCalendar * gregorian = [[NSCalendar alloc]
                               initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents * components =
    [gregorian components:
                 (NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit)
                 fromDate:[NSDate date]];
NSDate * today = [gregorian dateFromComponents:components];

Solution 5 - Ios

Working Swift 3 & 4 extension of the suggestion by Catfish_Man:

extension Date {

    func isToday() -> Bool {
        return Calendar.current.isDateInToday(self)
    }
    
}

Solution 6 - Ios

No need to juggle with components, eras and stuff.

NSCalendar provides an method to get the beginning of a certain time unit for an existing date.

This code will get the begin of today and another date and compare that. If it evaluates to NSOrderedSame, both dates are during the same day — so today.

NSDate *today = nil;
NSDate *beginningOfOtherDate = nil;

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

if([today compare:beginningOfOtherDate] == NSOrderedSame) {
    //otherDate is a date in the current day
}

Solution 7 - Ios

extension NSDate {
  func isToday() -> Bool {
	let cal = NSCalendar.currentCalendar()
	var components = cal.components([.Era, .Year, .Month, .Day], fromDate:NSDate())
	let today = cal.dateFromComponents(components)!
	
	components = cal.components([.Era, .Year, .Month, .Day], fromDate:self)
	let otherDate = cal.dateFromComponents(components)!
	
	return today.isEqualToDate(otherDate)
}

Worked for me on Swift 2.0

Solution 8 - Ios

Swift version of the best answer:

let cal = NSCalendar.currentCalendar()
var components = cal.components([.Era, .Year, .Month, .Day], fromDate:NSDate())
let today = cal.dateFromComponents(components)!

components = cal.components([.Era, .Year, .Month, .Day], fromDate:aDate);
let otherDate = cal.dateFromComponents(components)!

if(today.isEqualToDate(otherDate)) {
    //do stuff
}

Solution 9 - Ios

You could also check the time interval between the date you have, and the current date:

[myDate timeIntervalSinceNow]

This will give you the time interval, in seconds, between myDate and the current date/time.

Link.

Edit: Note to everyone: I'm well aware that [myDate timeIntervalSinceNow] does not unambiguously determine whether myDate is today.

I am leaving this answer as is so that if someone is looking for something similar and [myDate timeIntervalSinceNow] is useful, they may find it here.

Solution 10 - Ios

Refer to Apple's documentation entry entitled "Performing Calendar Calculations" [link].

Listing 13 on that page suggests that to determine the number of midnights between days, you use:

- (NSInteger)midnightsFromDate:(NSDate *)startDate toDate:(NSDate *)endDate
{
    NSCalendar *calendar = [NSCalendar autoupdatingCurrentCalendar];
    NSInteger startDay = [calendar ordinalityOfUnit:NSDayCalendarUnit
                                             inUnit:NSEraCalendarUnit
                                            forDate:startDate];
    NSInteger endDay = [calendar ordinalityOfUnit:NSDayCalendarUnit
                                           inUnit:NSEraCalendarUnit
                                          forDate:endDate];
    return endDay - startDay;
}

You may then determine if two days are the same by using that method and seeing if it returns 0 or not.

Solution 11 - Ios

Swift Extension based on the best answers:

extension NSDate {
    func isToday() -> Bool {
        let cal = NSCalendar.currentCalendar()
        if cal.respondsToSelector("isDateInToday:") {
            return cal.isDateInToday(self)
        }
        var components = cal.components((.CalendarUnitEra | .CalendarUnitYear | .CalendarUnitMonth | .CalendarUnitDay), fromDate:NSDate())
        let today = cal.dateFromComponents(components)!
        
        components = cal.components((.CalendarUnitEra | .CalendarUnitYear | .CalendarUnitMonth | .CalendarUnitDay), fromDate:self);
        let otherDate = cal.dateFromComponents(components)!
        return today.isEqualToDate(otherDate)
    }
}

Solution 12 - Ios

If you have a lot of these date comparisons, then the calls to calendar:components:fromDate start to take up a lot of time. According to some profiling I have done, they seem to be quite expensive.

Say you are trying to determine which from some array of dates, say NSArray *datesToCompare, are the same day as some given day, say NSDate *baseDate, then you can use something like the following (partly adapted from an answer above):

NSDate *baseDate = [NSDate date];

NSArray *datesToCompare = [NSArray arrayWithObjects:[NSDate date], 
                           [NSDate dateWithTimeIntervalSinceNow:100],
                           [NSDate dateWithTimeIntervalSinceNow:1000],
                           [NSDate dateWithTimeIntervalSinceNow:-10000],
                           [NSDate dateWithTimeIntervalSinceNow:100000],
                           [NSDate dateWithTimeIntervalSinceNow:1000000],
                           [NSDate dateWithTimeIntervalSinceNow:50],
                           nil];
                               
// determine the NSDate for midnight of the base date:
NSCalendar* calendar = [NSCalendar currentCalendar];
NSDateComponents* comps = [calendar components:(NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit) 
                                       fromDate:baseDate];
NSDate* theMidnightHour = [calendar dateFromComponents:comps];

// set up a localized date formatter so we can see the answers are right!
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateStyle:NSDateFormatterMediumStyle];
[dateFormatter setTimeStyle:NSDateFormatterMediumStyle];

// determine which dates in an array are on the same day as the base date:
for (NSDate *date in datesToCompare) {
    NSTimeInterval interval = [date timeIntervalSinceDate:theMidnightHour];
    if (interval >= 0 && interval < 60*60*24) {
        NSLog(@"%@ is on the same day as %@", [dateFormatter stringFromDate:date], [dateFormatter stringFromDate:baseDate]);
    }
    else {
        NSLog(@"%@ is NOT on the same day as %@", [dateFormatter stringFromDate:date], [dateFormatter stringFromDate:baseDate]);
    }
}

Output:

Nov 23, 2011 1:32:00 PM is on the same day as Nov 23, 2011 1:32:00 PM
Nov 23, 2011 1:33:40 PM is on the same day as Nov 23, 2011 1:32:00 PM
Nov 23, 2011 1:48:40 PM is on the same day as Nov 23, 2011 1:32:00 PM
Nov 23, 2011 10:45:20 AM is on the same day as Nov 23, 2011 1:32:00 PM
Nov 24, 2011 5:18:40 PM is NOT on the same day as Nov 23, 2011 1:32:00 PM
Dec 5, 2011 3:18:40 AM is NOT on the same day as Nov 23, 2011 1:32:00 PM
Nov 23, 2011 1:32:50 PM is on the same day as Nov 23, 2011 1:32:00 PM

Solution 13 - Ios

There is an easier way than many of the above answers!

NSDate *date = ... // The date you wish to test
NSCalendar *calendar = [NSCalendar currentCalendar];

if([calendar isDateInToday:date]) {
    //do stuff
}

Solution 14 - Ios

This could probably be reworked as an NSDate category, but i used:

// Seconds per day (24h * 60m * 60s)
#define kSecondsPerDay 86400.0f

+ (BOOL) dateIsToday:(NSDate*)dateToCheck
{
	// Split today into components
	NSCalendar* gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
	NSDateComponents* comps = [gregorian components:(NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit|NSHourCalendarUnit|NSMinuteCalendarUnit|NSSecondCalendarUnit) 
										fromDate:[NSDate date]];

	// Set to this morning 00:00:00
	[comps setHour:0];
	[comps setMinute:0];
	[comps setSecond:0];
	NSDate* theMidnightHour = [gregorian dateFromComponents:comps];
	[gregorian release];
	
	// Get time difference (in seconds) between date and then
	NSTimeInterval diff = [dateToCheck timeIntervalSinceDate:theMidnightHour];
	return ( diff>=0.0f && diff<kSecondsPerDay );
}

(However, comparing the two date strings as in the original question almost feels 'cleaner'..)

Solution 15 - Ios

for iOS7 and earlier:

//this is now => need that for the current date
NSDate * now = [NSDate date];

NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
[calendar setTimeZone:[NSTimeZone systemTimeZone]];
    
NSDateComponents * components = [calendar components:( NSYearCalendarUnit|    NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit) fromDate: now];
    
[components setMinute:0];
[components setHour:0];
[components setSecond:0];
    
//this is Today's Midnight
NSDate *todaysMidnight = [calendar dateFromComponents: components];



//now timeIntervals since Midnight => in seconds
NSTimeInterval todayTimeInterval = [now timeIntervalSinceDate: todaysMidnight];

//now timeIntervals since OtherDate => in seconds
NSTimeInterval otherDateTimeInterval = [now timeIntervalSinceDate: otherDate];
    
if(otherDateTimeInterval > todayTimeInterval) //otherDate is not in today
{
    if((otherDateTimeInterval - todayTimeInterval) <= 86400) //86400 == a day total seconds
    {
        @"yesterday";
    }
    else
    {
        @"earlier";
    }
}
else
{
    @"today";
}


now = nil;
calendar = nil;
components = nil;
todaysMidnight = nil;

NSLog("Thank you :-)");

Solution 16 - Ios

Check our Erica Sadun's great NSDate extension. Very simple to use. Fine it here:

http://github.com/erica/NSDate-Extensions

It's already there in this post: https://stackoverflow.com/a/4052798/362310

Solution 17 - Ios

The correct and safe solution without force-unwrapping, working on Swift 2.2 and before iOS 8:

func isToday() -> Bool {
    let calendar = NSCalendar.currentCalendar()
    if #available(iOS 8.0, *) {
        return calendar.isDateInToday(self)
    }
    
    let todayComponents = calendar.components([.Era, .Year, .Month, .Day], fromDate:NSDate())
    let dayComponents = calendar.components([.Era, .Year, .Month, .Day], fromDate:self)

    guard let today = calendar.dateFromComponents(todayComponents),
        day = calendar.dateFromComponents(dayComponents) else {
        return false
    }
    
    return today.compare(day) == .OrderedSame
}

Solution 18 - Ios

Here's my 2 cent answer building on the accepted answer but supporting the newer API as well. Note: I use the Gregorian calendar as most time stamps are GMT but change yours as you see fit

func isDateToday(date: NSDate) -> Bool {
    let calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)!
    if calendar.respondsToSelector("isDateInToday:") {
        return calendar.isDateInToday(date)
    }
    let dateComponents = NSCalendarUnit.CalendarUnitYear | NSCalendarUnit.CalendarUnitMonth | NSCalendarUnit.CalendarUnitDay
    let today = calendar.dateFromComponents(calendar.components(dateComponents, fromDate: NSDate()))!
    let dateToCompare = calendar.dateFromComponents(calendar.components(dateComponents, fromDate: date))!
    
    return dateToCompare == today
}

Solution 19 - Ios

My solution is calculate how much days passed since 1970 by division and compare the integer part

#define kOneDay (60*60*24)
- (BOOL)isToday {
  NSInteger offset = [[NSTimeZone defaultTimeZone] secondsFromGMT];

  NSInteger days =[self timeIntervalSince1970] + offset;
  NSInteger currentDays = [[NSDate date] timeIntervalSince1970] + offset;
  return (days / kOneDay == currentDays / kOneDay);
}

Solution 20 - Ios

NSDate *dateOne = yourDate;
NSDate *dateTwo = [NSDate date];  
  
switch ([dateOne compare:dateTwo])
{  
    case NSOrderedAscending:  
        NSLog(@”NSOrderedAscending”);  
        break;  
    
    case NSOrderedSame: 
        NSLog(@”NSOrderedSame”);  
        break;

    case NSOrderedDescending:  
        NSLog(@”NSOrderedDescending”);  
        break;  
}  

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
QuestionSeunghoonView Question on Stackoverflow
Solution 1 - IosCatfish_ManView Answer on Stackoverflow
Solution 2 - IosDavid KanarekView Answer on Stackoverflow
Solution 3 - IosJonView Answer on Stackoverflow
Solution 4 - IosstefanBView Answer on Stackoverflow
Solution 5 - IosBenno KressView Answer on Stackoverflow
Solution 6 - IosvikingosegundoView Answer on Stackoverflow
Solution 7 - IosOmar AlbeikView Answer on Stackoverflow
Solution 8 - IosVojtech VrbkaView Answer on Stackoverflow
Solution 9 - IosalesplinView Answer on Stackoverflow
Solution 10 - IosArtOfWarfareView Answer on Stackoverflow
Solution 11 - IosZiggySTView Answer on Stackoverflow
Solution 12 - IosJulian RichardsonView Answer on Stackoverflow
Solution 13 - IosarylandView Answer on Stackoverflow
Solution 14 - IosLeoNView Answer on Stackoverflow
Solution 15 - Iosuser3744424View Answer on Stackoverflow
Solution 16 - IosVaibhav SaranView Answer on Stackoverflow
Solution 17 - Iosfpg1503View Answer on Stackoverflow
Solution 18 - IosDaniel GalaskoView Answer on Stackoverflow
Solution 19 - IosstcuiView Answer on Stackoverflow
Solution 20 - IosrajeshView Answer on Stackoverflow