Number of days between two NSDates

IosObjective CCocoa TouchNsdate

Ios Problem Overview


How could I determine the number of days between two NSDate values (taking into consideration time as well)?

The NSDate values are in whatever form [NSDate date] takes.

Specifically, when a user enters the inactive state in my iPhone app, I store the following value:

exitDate = [NSDate date];

And when they open the app back up, I get the current time:

NSDate *now = [NSDate date];

Now I'd like to implement the following:

-(int)numberOfDaysBetweenStartDate:exitDate andEndDate:now

Ios Solutions


Solution 1 - Ios

Here's an implementation I used to determine the number of calendar days between two dates:

+ (NSInteger)daysBetweenDate:(NSDate*)fromDateTime andDate:(NSDate*)toDateTime
{
	NSDate *fromDate;
	NSDate *toDate;
   
	NSCalendar *calendar = [NSCalendar currentCalendar];
   
	[calendar rangeOfUnit:NSCalendarUnitDay startDate:&fromDate
		interval:NULL forDate:fromDateTime];
	[calendar rangeOfUnit:NSCalendarUnitDay startDate:&toDate
		interval:NULL forDate:toDateTime];
   
	NSDateComponents *difference = [calendar components:NSCalendarUnitDay
		fromDate:fromDate toDate:toDate options:0];
   
	return [difference day];
}

EDIT:

Fantastic solution above, here's Swift version below as an extension on NSDate:

extension NSDate {
  func numberOfDaysUntilDateTime(toDateTime: NSDate, inTimeZone timeZone: NSTimeZone? = nil) -> Int {
    let calendar = NSCalendar.currentCalendar()
    if let timeZone = timeZone {
      calendar.timeZone = timeZone
    }
  
    var fromDate: NSDate?, toDate: NSDate?
  
    calendar.rangeOfUnit(.Day, startDate: &fromDate, interval: nil, forDate: self)
    calendar.rangeOfUnit(.Day, startDate: &toDate, interval: nil, forDate: toDateTime)
  
    let difference = calendar.components(.Day, fromDate: fromDate!, toDate: toDate!, options: [])
    return difference.day
  }
}

A bit of force unwrapping going on which you may want to remove depending on your use case.

The above solution also works for time zones other than the current time zone, perfect for an app that shows information about places all around the world.

Solution 2 - Ios

Here's the best solution I've found. Seems to utilize the Apple approved method for determining any amount of units between NSDates.

- (NSInteger)daysBetween:(NSDate *)dt1 and:(NSDate *)dt2
{
    NSUInteger unitFlags = NSCalendarUnitDay;
    NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
    NSDateComponents *components = [calendar components:unitFlags fromDate:dt1 toDate:dt2 options:0];
    return [components day] + 1;
}

E.g. if you want months as well, then you could include 'NSMonthCalendarUnit' as a unitFlag.

To credit the original blogger, I found this info here (although there was a slight mistake that I've fixed above): http://cocoamatic.blogspot.com/2010/09/nsdate-number-of-days-between-two-dates.html?showComment=1306198273659#c6501446329564880344

Solution 3 - Ios

Swift 3.0 Update

extension Date {
    
    func differenceInDaysWithDate(date: Date) -> Int {
        let calendar = Calendar.current
        
        let date1 = calendar.startOfDay(for: self)
        let date2 = calendar.startOfDay(for: date)
        
        let components = calendar.dateComponents([.day], from: date1, to: date2)
        return components.day ?? 0
    }
}

Swift 2.0 Update

extension NSDate {
    
    func differenceInDaysWithDate(date: NSDate) -> Int {
        let calendar: NSCalendar = NSCalendar.currentCalendar()
        
        let date1 = calendar.startOfDayForDate(self)
        let date2 = calendar.startOfDayForDate(date)
        
        let components = calendar.components(.Day, fromDate: date1, toDate: date2, options: [])
        return components.day
    }
    
}

Original Solution

Another solution in Swift.

If your purpose is to get the exact day number between two dates, you can work around this issue like this:

// Assuming that firstDate and secondDate are defined
// ...

var calendar: NSCalendar = NSCalendar.currentCalendar()

// Replace the hour (time) of both dates with 00:00
let date1 = calendar.startOfDayForDate(firstDate)
let date2 = calendar.startOfDayForDate(secondDate)

let flags = NSCalendarUnit.DayCalendarUnit
let components = calendar.components(flags, fromDate: date1, toDate: date2, options: nil)

components.day  // This will return the number of day(s) between dates

Solution 4 - Ios

I use this as category method for NSDate class

// returns number of days (absolute value) from another date (as number of midnights beween these dates)
- (int)daysFromDate:(NSDate *)pDate {
    NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
    NSInteger startDay=[calendar ordinalityOfUnit:NSCalendarUnitDay
                                           inUnit:NSCalendarUnitEra
                                          forDate:[NSDate date]];
    NSInteger endDay=[calendar ordinalityOfUnit:NSCalendarUnitDay
                                         inUnit:NSCalendarUnitEra
                                        forDate:pDate];
    return abs(endDay-startDay);
}

Solution 5 - Ios

I needed the number of days between two dates including the beginning day. e.g. days between 14-2-2012 and 16-2-2012 would produce a result of 3.

+ (NSInteger)daysBetween:(NSDate *)dt1 and:(NSDate *)dt2 {
        NSUInteger unitFlags = NSDayCalendarUnit;
        NSCalendar* calendar = [NSCalendar currentCalendar];
        NSDateComponents *components = [calendar components:unitFlags fromDate:dt1 toDate:dt2 options:0];
        NSInteger daysBetween = abs([components day]);
    return daysBetween+1;
}

Note that it doesn't matter in which order you provide the dates. It will always return a positive number.

Solution 6 - Ios

NSDate *lastDate = [NSDate date];
NSDate *todaysDate = [NSDate date];
NSTimeInterval lastDiff = [lastDate timeIntervalSinceNow];
NSTimeInterval todaysDiff = [todaysDate timeIntervalSinceNow];
NSTimeInterval dateDiff = lastDiff - todaysDiff;

dateDiff will then be the number of second between the two dates. Just divide by the number of seconds in a day.

Solution 7 - Ios

@Brian

Brian's answer while good, only calculates difference in days in terms of 24h chunks, but not calendar day differences. For example 23:59 on Dec 24th is only 1 minute away from Christmas Day, for the purpose of many application that is considered one day still. Brian's daysBetween function would return 0.

Borrowing from Brian's original implementation and beginning/end of day, I use the following in my program: (https://stackoverflow.com/questions/13324633/nsdate-beginning-of-day-and-end-of-day)

- (NSDate *)beginningOfDay:(NSDate *)date
{
    NSCalendar *cal = [NSCalendar currentCalendar];
    NSDateComponents *components = [cal components:( NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit ) fromDate:date];
    [components setHour:0];
    [components setMinute:0];
    [components setSecond:0];
    return [cal dateFromComponents:components];
}

- (NSDate *)endOfDay:(NSDate *)date
{
    NSCalendar *cal = [NSCalendar currentCalendar];
    NSDateComponents *components = [cal components:( NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit ) fromDate:date];
    [components setHour:23];
    [components setMinute:59];
    [components setSecond:59];
    return [cal dateFromComponents:components];
}

- (int)daysBetween:(NSDate *)date1 and:(NSDate *)date2 {
    NSDate *beginningOfDate1 = [self beginningOfDay:date1];
    NSDate *endOfDate1 = [self endOfDay:date1];
    NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
    NSDateComponents *beginningDayDiff = [calendar components:NSDayCalendarUnit fromDate:beginningOfDate1 toDate:date2 options:0];
    NSDateComponents *endDayDiff = [calendar components:NSDayCalendarUnit fromDate:endOfDate1 toDate:date2 options:0];
    if (beginningDayDiff.day > 0)
        return beginningDayDiff.day;
    else if (endDayDiff.day < 0)
        return endDayDiff.day;
    else {
        return 0;
    }
}

Solution 8 - Ios

Another approach:

NSDateFormatter* dayFmt = [[NSDateFormatter alloc] init];
[dayFmt setTimeZone:<whatever time zone you want>];
[dayFmt setDateFormat:@"g"];
NSInteger firstDay = [[dayFmt stringFromDate:firstDate] integerValue];    
NSInteger secondDay = [[dayFmt stringFromDate:secondDate] integerValue];
NSInteger difference = secondDay - firstDay;

Has the advantage over the timeIntervalSince... scheme that timezone can be taken into account, and there's no ambiguity with intervals a few seconds short or long of one day.

And a bit more compact and less confusing than the NSDateComponents approaches.

Solution 9 - Ios

Just adding an answer for those who visit this page trying to do this in Swift. The approach is pretty much the same.

private class func getDaysBetweenDates(startDate:NSDate, endDate:NSDate) -> NSInteger {

    var gregorian: NSCalendar = NSCalendar.currentCalendar();
    let flags = NSCalendarUnit.DayCalendarUnit
    let components = gregorian.components(flags, fromDate: startDate, toDate: endDate, options: nil)
    
    return components.day
}

This answer was found here, in the discussion section of the following method:

components(_:fromDate:toDate:options:)

Solution 10 - Ios

Here is an implementation of Brian's function in Swift:

class func daysBetweenThisDate(fromDateTime:NSDate, andThisDate toDateTime:NSDate)->Int?{
    
    var fromDate:NSDate? = nil
    var toDate:NSDate? = nil
    
    let calendar = NSCalendar.currentCalendar()
    
    calendar.rangeOfUnit(NSCalendarUnit.DayCalendarUnit, startDate: &fromDate, interval: nil, forDate: fromDateTime)
    
    calendar.rangeOfUnit(NSCalendarUnit.DayCalendarUnit, startDate: &toDate, interval: nil, forDate: toDateTime)
    
    if let from = fromDate {

        if let to = toDate {

            let difference = calendar.components(NSCalendarUnit.DayCalendarUnit, fromDate: from, toDate: to, options: NSCalendarOptions.allZeros)
            
            return difference.day
        }
    }
    
    return nil
}

Solution 11 - Ios

Do you mean calendar days or 24-hour periods? i.e. is Tuesday at 9PM a day before Wednesday at 6AM, or less than one day?

If you mean the former, it's a bit complicated and you'll have to resort to manipulations via NSCalendar and NSDateComponent which I don't recall off the top of my head.

If you mean the latter, just get the dates' time intervals since the reference date, subtract one from the other, and divide by 24 hours (24 * 60 * 60) to get the approximate interval, leap seconds not included.

Solution 12 - Ios

Why not just:

int days = [date1 timeIntervalSinceDate:date2]/24/60/60;

Solution 13 - Ios

Got one, not sure it's exactly what you want, but it could help some of you, (helped me!!)

My goal was to know if, between two date (less than 24h difference) i had a "overday" day+1:

i did the following (a bit archaic i admit)

NSDate *startDate = ...
NSDate *endDate = ...

NSDate already formatted by another NSDateFormatter (this one is just for this purpose :)

NSDateFormatter *dayFormater = [[NSDateFormatter alloc]init];
[dayFormater setDateFormat:@"dd"];

int startDateDay = [[dayFormater stringFromDate:startDate]intValue];

int endDateDay = [[dayFormater stringFromDate:dateOn]intValue];

if (endDateDay > startDateDay) {
    NSLog(@"day+1");
} else {
    NSLog(@"same day");
}

maybe something like this already exist, but didn't find it

Tim

Solution 14 - Ios

The solution I found was:

+(NSInteger)getDaysDifferenceBetween:(NSDate *)dateA and:(NSDate *)dateB {

  if ([dateA isEqualToDate:dateB]) 
	return 0;
	 
  NSCalendar * gregorian = 
        [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];



  NSDate * dateToRound = [dateA earlierDate:dateB];
  int flags = (NSYearCalendarUnit | NSMonthCalendarUnit |  NSDayCalendarUnit);
  NSDateComponents * dateComponents = 
         [gregorian components:flags fromDate:dateToRound];


  NSDate * roundedDate = [gregorian dateFromComponents:dateComponents];

  NSDate * otherDate = (dateToRound == dateA) ? dateB : dateA ;

  NSInteger diff = abs([roundedDate timeIntervalSinceDate:otherDate]);

  NSInteger daysDifference = floor(diff/(24 * 60 * 60));

  return daysDifference;
}

Here I am effectively rounding the first date to start from the beginning of the day and then calculating the difference as Jonathan is suggesting above...

Solution 15 - Ios

I have published an open-source class/library to do just this.

Have a look at RelativeDateDescriptor, which can be used to obtain the time difference as follows...

RelativeDateDescriptor *descriptor = [[RelativeDateDescriptor alloc] initWithPriorDateDescriptionFormat:@"%@ ago" postDateDescriptionFormat:@"in %@"];

// date1: 1st January 2000, 00:00:00
// date2: 6th January 2000, 00:00:00
[descriptor describeDate:date2 relativeTo:date1]; // Returns '5 days ago'
[descriptor describeDate:date1 relativeTo:date2]; // Returns 'in 5 days'

Solution 16 - Ios

Why note use the following NSDate method:

- (NSTimeInterval)timeIntervalSinceDate:(NSDate *)anotherDate

This will return the number of seconds between your two dates and you can divide by 86,400 to get the number of days !!

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
QuestionCodeGuyView Question on Stackoverflow
Solution 1 - IosBrianView Answer on Stackoverflow
Solution 2 - IosBiosopherView Answer on Stackoverflow
Solution 3 - IosEmin Bugra SaralView Answer on Stackoverflow
Solution 4 - IosjkiView Answer on Stackoverflow
Solution 5 - IosorkodenView Answer on Stackoverflow
Solution 6 - Ioschris View Answer on Stackoverflow
Solution 7 - IostoonizView Answer on Stackoverflow
Solution 8 - IosHot LicksView Answer on Stackoverflow
Solution 9 - IosMihirView Answer on Stackoverflow
Solution 10 - IosPJeremyMaloufView Answer on Stackoverflow
Solution 11 - IosJonathan GrynspanView Answer on Stackoverflow
Solution 12 - IosMyCSharpCornerView Answer on Stackoverflow
Solution 13 - IosTimView Answer on Stackoverflow
Solution 14 - IosMichael MichailidisView Answer on Stackoverflow
Solution 15 - IosmmccombView Answer on Stackoverflow
Solution 16 - IosErwanView Answer on Stackoverflow