How can I get the exact difference (in decimal) between 2 values of NSDate
.
Eg. Jan 15 2016 to Jul 15 2017 = 1.5 Years.
I can use something like:
NSCalendar.currentCalendar().components(NSCalendarUnit.CalendarUnitYear, fromDate: date1, toDate: date1, options: nil).year
but this gives me absolute values. i.e. for above example it would give me 1 Year. Is it possible to get exact values correct to at least a few decimal places?
There isn't a perfect answer to this question. Different years are slightly different lengths. You have to make some assumptions.
If you assume 365.2425 days per year, with each day having 24 hours, then the calculation is trivial:
But there are lots of edge cases and weirdness to deal with. Because of leap years, some years have 365 days, and some have 366. Then there's leap seconds.
If you get rid of months in @CodeDifferent's answer then you'll get an answer that allows for leap days between the dates.
But, as Code Different pointed out, his answer as written actually gives answers that seem more accurate, even though they are not. (A difference of 3 months will always yield .25 years, and will ignore longer/shorter months. Is that the right thing to do? Depends on your goal and your assumptions.)
The terms you've used here are misleading. When you say "absolute" you mean "integral." And when you say "exact" you mean "within some desired precision."
Let's say the precision you wanted was 2 decimal places, so we'd need to measure a year to 1%. That's larger than a day, so tracking days is sufficient. If you needed more precision, then you could expand this technique, but if you push it too far, "year" gets more tricky, and you have to start asking what you mean by "a year."
Avoid asking this question when you can. Many answers here say things like "there are 365.25 days in a year." But try adding "365.25 * 24 hours" to "right now" and see if you get "the same date and time next year." While it may seem correct "on average," it is actually wrong 100% of the time for calendar dates. (It works out here because it's within 1%, but so would 365, 366, or even 363.)
We avoid this madness by saying "1% is close enough for this problem."
That said, in most cases you shouldn't be doing this. Since iOS 8, the preferred tool is
NSDateComponentsFormatter
. You won't get this precise format (i.e. fractional years), but you'll get a nicely localized result that takes most issues into account across different cultures.Since you mentioned that your goal is something you can display to users as a meaningful indication of the time between two dates, you might find it easier to use
NSDateComponentsFormatter
. For example:This gives you a string that reads "1 year, 6 months". It's not exactly what you specified as your goal, but it's a clear indication for users and avoids a lot of complexity. There's a property on
NSDateComponentsFormatter
calledallowsFractionalUnits
that's supposed to lead to results like "1.5 years", but it doesn't seem to work right now. (Even if you limit theallowedUnits
to only.Year
, you still don't get a fractional year. I'm off to file a bug with Apple...). You can tweakallowedUnits
to get whatever granularity you like, and useincludesApproximationPhrase
to have the class add a localized version of "About..." to the resulting string if it's not precise. If you have some flexibility in your final format, this would be a really good solution.According to NASA, there are 365.2422 days per year on average. Here, I round that up to 365.25 days per year:
Obviously, this depends on your assumptions. If you want to count of leap days between
fromDate
andtoDate
, it will be more complicated.Some sample outputs: