I have 2 dates that I would like to compare. A date in the future, and the current date. When I compare them I want to retrieve their difference in terms of hours, minutes, and seconds. I believe the code I have to do this is correct, however, I get different values returned depending on the components I request.
I am using the following calendar for all examples:
let calendar = NSCalendar.currentCalendar()
A:
let dateComponents = calendar.components([NSCalendarUnit.Year, NSCalendarUnit.Month, NSCalendarUnit.Day, NSCalendarUnit.Hour, NSCalendarUnit.Second, NSCalendarUnit.Minute], fromDate: NSDate(), toDate: date, options: [])
B:
let dateComponents2 = calendar.components(.Hour, fromDate: NSDate(), toDate: date, options: [])
So, with the above example, dateComponents.hour
does not equal dateComponents2.hour
, and dateComponents2.hour
returns the correct value.
Even more interesting is the following case:
A:
let dateComponents = calendar.components([NSCalendarUnit.Year, NSCalendarUnit.Month, NSCalendarUnit.Day, NSCalendarUnit.Hour, NSCalendarUnit.Second, NSCalendarUnit.Minute], fromDate: NSDate(), toDate: date, options: [])
B:
let dateComponents2 = calendar.components(.Minute, fromDate: NSDate(), toDate: date, options: [])
Now, dateComponents.minute
does not equal dateComponents2.minute
, but now dateComponents.minute
returns the correct value.
Why could this be happening? Does the fact that I am requesting multiple components at the same time affect the return value?
EDIT Here are some examples using the following dates. The return values are shown as hours, minutes, seconds:
2015-11-29 10:59:00 +0000
2015-11-28 07:57:20 +0000
Using dateComponents:
3, 1, 39
Using dateComponents2 (one for each component):
27, 1621, 97299
The hours value is correct from dateComponents2, and the minutes and seconds values are correct from dateComponents.
Let's imagine that the two NSDate
objects are 61 seconds apart, if you get both minute and second at the same time, you get 1 minute and 1 second, but if you just ask for just seconds, you get 61 seconds:
let date1 = NSDate()
let date2 = date1.dateByAddingTimeInterval(61)
let calendar = NSCalendar.currentCalendar()
let components1 = calendar.components([.Minute, .Second], fromDate: date1, toDate: date2, options: [])
let components2 = calendar.components([.Second], fromDate: date1, toDate: date2, options: [])
print("\(components1.minute) minute and \(components1.second) second")
print("\(components2.second) seconds")
That yields:
1 minute and 1 second
61 seconds
Using your dates (and adding days and hours to the calculations):
let dateString1 = "2015-11-28 07:57:20 +0000"
let dateString2 = "2015-11-29 10:59:00 +0000"
let formatter = NSDateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z"
let date1 = formatter.dateFromString(dateString1)!
let date2 = formatter.dateFromString(dateString2)!
let calendar = NSCalendar.currentCalendar()
let components1 = calendar.components([.Day, .Hour, .Minute, .Second], fromDate: date1, toDate: date2, options: [])
let components2 = calendar.components([.Second], fromDate: date1, toDate: date2, options: [])
print("\(components1.day) day, \(components1.hour) hours, \(components1.minute) minute, and \(components1.second) seconds")
print("\(components2.second) seconds")
That yields:
1 day, 3 hours, 1 minute, and 40 seconds
97300 seconds
And if you multiply that out, you'll see that 1 day, 3 hours, 1 minute and 40 seconds is equal to 97300 seconds.
You can also consider using NSDateComponentsFormatter
to create a nicely formatted (and localized) string representation of the time elapsed:
let componentsFormatter = NSDateComponentsFormatter()
componentsFormatter.allowedUnits = [.Day, .Hour, .Minute, .Second]
componentsFormatter.unitsStyle = .Full
print(componentsFormatter.stringFromDate(date1, toDate: date2))
// or just show the top two units (because if you're showing days/hours, you probably no longer care about minutes/seconds
componentsFormatter.maximumUnitCount = 2
print(componentsFormatter.stringFromDate(date1, toDate: date2))
// but if you want actual total number of seconds, then change `allowedUnits` to use only that
componentsFormatter.allowedUnits = [.Second]
print(componentsFormatter.stringFromDate(date1, toDate: date2))
That will display three optional strings:
1 day, 3 hours, 1 minute, 40 seconds
1 day, 3 hours
97,300 seconds