11

Is there any way to find out an accurate difference between two NSDate?

I have found solutions but they aren't accurate enough. I need to take into account daylight saving, the fact that different months have a different number of days, etc.

A simple calculation such as /60/60/24 etc. to work out minutes, hours and days doesn't take them into account.

Lets say I need to work out the difference between the time right now ([NSDate date]) and December 25th 10:22PM (date chosen by user using date picker [datePicker date]) just as an example, how would I do this?
Knowing the exact time difference isn't the key, so long as I have an accurate difference of days, months and years, it will do.

SwiftArchitect
  • 47,376
  • 28
  • 140
  • 179
Josh Kahane
  • 16,765
  • 45
  • 140
  • 253
  • http://stackoverflow.com/questions/1237778/how-do-i-break-down-an-nstimeinterval-into-year-months-days-hours-minutes-an possible dupplicate – d.lebedev Dec 05 '11 at 15:31
  • 1
    Calendrical calculation is hard. Smart people regularly get it wrong. The biggest trap is believing it to be simple. Take it slow and expect to make mistakes along the way. The thing to note is Cocoa provides great tools for doing it right, but seemingly no easy convenient do what I mean tools. Step one is read and reread the docs and second guess your understanding. It takes a clear understanding of them to fully define your actual problem and solution. It can be frustrating, but they actually provide tools that force you to do it right (after a bit of struggle) – uchuugaka Jul 25 '13 at 13:03

4 Answers4

25

From Apple's Date & Time Programming Guide:

Listing 12 Getting the difference between two dates

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

NSCalendar *gregorian = [[NSCalendar alloc]
                 initWithCalendarIdentifier:NSGregorianCalendar];

NSUInteger unitFlags = NSMonthCalendarUnit | NSDayCalendarUnit;

NSDateComponents *components = [gregorian components:unitFlags
                                          fromDate:startDate
                                          toDate:endDate options:0];
NSInteger months = [components month];
NSInteger days = [components day];
Darek Rossman
  • 1,323
  • 1
  • 10
  • 12
15

NSDate is completely independent of Timezone. Daylight saving doesn't even come into the picture for NSDate. Only when you convert NSDate into a human readable format (MM/DD/YY, HH:MM:SS format or the like), does Time Zone come into picture.

Make sure that you take into account correct timezone, day-light saving setting when you create NSDate(s). Subsequently, the method, [date1 timeIntervalSinceDate:date2] should always give you accurate time difference.

Sanjay Chaudhry
  • 3,181
  • 1
  • 22
  • 31
  • 1
    Trouble is with that method is that I get an accurate number os seconds between the two dates but then diving that down into days, months and years is inaccurate as it would be too complex to take into account how manes days are in that month or year, change the divider. Understand? Which is why I have avoided this. – Josh Kahane Dec 05 '11 at 15:39
  • Sanjay Chaudhry' answer answers your question. I guess you didn't ask a precise enough question. – ader Dec 05 '11 at 15:51
2

So, the more accurate question you meant to ask was: How can I get a nicely formatted days, months, years from a difference between two dates. First you want to get the nsTimerInterval (time difference in seconds) and then format it:

How do I break down an NSTimeInterval into year, months, days, hours, minutes and seconds on iPhone?

Community
  • 1
  • 1
ader
  • 5,403
  • 1
  • 21
  • 26
0

Small update on the code for latest iOS:

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

NSCalendar *gregorian = [[NSCalendar alloc]
                             initWithCalendarIdentifier:NSCalendarIdentifierGregorian];

NSUInteger unitFlags = NSCalendarUnitMonth | NSCalendarUnitDay;

NSDateComponents *components = [gregorian components:unitFlags
                                            fromDate: startDate
                                              toDate:endDate options:0];
NSInteger months = [components month];
NSInteger days = [components day];
Symanski
  • 337
  • 3
  • 11