Binary floating point number can not represent all numbers
exactly, therefore your code is prone to rounding errors.
Example (Swift 2):
let decimalHour = 1.0 + 5.0/60.0
print(decimalHour.debugDescription) // 1.0833333333333333
print(floor(decimalHour * 3600)) // 3899.0
let hours = Int(floor(decimalHour))
let mins = Int(floor(decimalHour * 60) % 60)
let secs = Int(floor(decimalHour * 3600) % 60)
print(hours, mins, secs) // 1 5 59
The actual number stored in decimalHour
is slightly less than 1 + 5/60
, and therefore the seconds are calculated wrongly.
(Also note that you cannot use %
with floating point numbers
in Swift 3, compare What does "% is unavailable: Use truncatingRemainder instead" mean?.)
As already said in the comments, a better approach would be
to store the duration as an integer (number of seconds).
If that is not possible, round the floating point number to
a the number of seconds and then continue with pure integer
arithmetic. Example (works with Swift 2+3):
let decimalHour = 1.0 + 5.0/60.0
let totalSeconds = lrint(decimalHour * 3600) // round to seconds
let hours = totalSeconds / 3600
let mins = (totalSeconds % 3600) / 60
let secs = totalSeconds % 60
print(hours, mins, secs) // 1 5 0