Reputation: 315
I want to store duration of time in a Double
and need to extract high and low values of Double
(hour and minute) for accessing them. I also need to be able to set Double
with two Ints
(hour
and minute
).
And I got something here now:
extension Double {
func hour() -> Int {
return NSNumber(double: floor(self)).integerValue
}
func minute() -> Int {
return NSNumber(float: Float(Double((self - floor(self)) * 100))).integerValue
}
init(hour: Int, minute: Int) {
self = Double(hour) + ( Double(minute) / 100 )
}
}
And then I've performed some testing with this in my appDelegate's didFinishLaunchingWithOptions
:
var time: Double = 18.30
NSLog("Time is \"%f\" - so hours is \"%d\" and minutes is \"%d\".", time, time.hour(), time.minute())
time = Double(hour: 10, minute: 1)
NSLog("Time is \"%f\" - so hours is \"%d\" and minutes is \"%d\".", time, time.hour(), time.minute())
time = Double(hour: 15, minute: 45)
NSLog("Time is \"%f\" - so hours is \"%d\" and minutes is \"%d\".", time, time.hour(), time.minute())
Now, this code works. One might wonder why I convert Double
to Float
in the minute()
function. This is because of an unknown issue that I faced when using Double
s without converting them to Float
s before converting these Float
s to Int
s. If minutes didn't end with 0
, one minute was subtracted for unknown reasons.
For example, 10:42 returned 10 hours and 41 minutes.
But 10:30 was still 10 hours and 30 minutes.
Also 10:00 was 10 hours and 0 minutes.
This routine that I posted here seems to be working, but I was just wondering, if I am as efficient as possible... There's more conversion here than what would be needed.
So, any improvements?
And does someone know the reason for unknown issue with decremented minute I mentioned?
Upvotes: 1
Views: 475
Reputation: 539975
A binary floating point number such as Double
or Float
cannot represent the number 10.42
exactly, therefore
multiplying the fractional part by 100 and truncating the result might give 41
.
With the conversion to Float
you are just "hiding" the problem.
Here is a version that rounds instead of truncating, and is overall a bit simpler. I have adopted the notation of "minute" from your code, even if it represents 1/100 of an hour and not 1/60.
extension Double {
func hour() -> Int {
return Int(self)
}
func minute() -> Int {
return Int(round(self * 100.0)) % 100
}
init(hour: Int, minute: Int) {
self = Double(hour) + ( Double(minute) / 100 )
}
}
Other possible approaches to solve your problem:
Store the duration as an integer representing the total
number of minutes. E.g. "10:42" would be stored as 10*60 + 42
.
Then you have no rounding problems at all.
Use the Foundation
type NSDecimalNumber
instead of Double
, which can represent
a decimal integer with up to 38 digits exactly.
Upvotes: 1