您在此处使用的术语具有误导性。当您说“绝对”时,您的意思是“整体”。当您说“精确”时,您的意思是“在某个所需的精度范围内”。
假设您想要的精度是小数点后 2 位,所以我们需要测量一年到 1%。这比一天大,因此跟踪天数就足够了。如果您需要更高的精确度,那么您可以扩展这项技术,但如果您将其推得太远,“年”会变得更加棘手,您必须开始问“一年”是什么意思。
尽可能避免问这个问题。这里的许多答案都说“一年有 365.25 天”。但是尝试将“365.25 * 24 小时”添加到“现在”,看看是否会得到“明年相同的日期和时间”。虽然“平均而言”看起来是正确的,但实际上 100% 的日历日期都是错误的。 (它在这里有效,因为它在 1% 以内,但 365、366 甚至 363 也是如此。)
我们通过说“1% 就足以解决这个问题”来避免这种疯狂。
// What calendar do you *really* mean here? The user's current calendar,
// or the Gregorian calendar? The below code should work for any calendar,
// because every calendar's year is made up of some number of days, but it's
// worth considering if you really mean (and are testing) arbitrary calendars.
// If you mean "Gregorian," then use NSCalendar(identifier: NSCalendarIdentifierGregorian)!
let calendar = NSCalendar.currentCalendar()
// Determine how many integral days are between the dates
let diff = calendar.components(.Day, fromDate: date1, toDate: date2, options: [])
// Determine how many days are in a year. If you really meant "Gregorian" above, and
// so used calendarWithIdentifer rather than currentCalendar, you can estimate 365 here.
// Being within one day is inside the noise floor of 1%.
// Yes, this is harder than you'd think. This is based on MartinR's code: http://stackoverflow.com/a/16812482/97337
var startOfYear: NSDate? = nil
var lengthOfYear = NSTimeInterval(0)
calendar.rangeOfUnit(.Year, startDate: &startOfYear, interval: &lengthOfYear, forDate: date1)
let endOfYear = startOfYear!.dateByAddingTimeInterval(lengthOfYear)
let daysInYear = calendar.components(.Day, fromDate: startOfYear!, toDate: endOfYear, options: []).day
// Divide
let fracDiff = Double(diff.day) / Double(daysInYear)
也就是说,在大多数情况下,您不应该这样做。从 iOS 8 开始,首选工具是 NSDateComponentsFormatter。您不会得到这种精确的格式(即分数年),但您会得到一个很好的本地化结果,它考虑了不同文化中的大多数问题。
let formatter = NSDateComponentsFormatter()
formatter.unitsStyle = .Full
formatter.includesApproximationPhrase = true
formatter.allowedUnits = [.Year, .Month]
formatter.allowsFractionalUnits = true
formatter.stringFromDate(date1, toDate: date2)
// About 1 year, 6 months