Swift 2 get minutes and seconds from double - time

I am currently storing time in seconds (for example 70.149 seconds). How would I easily get the minutes and seconds? What I mean is 70.149 seconds is 1min and 10sec. How would I be able to do this easily in swift?
Here is an example of what I want to do.
let time:Double = 70.149 //This can be any value
let mins:Int = time.minutes //In this case it would be 1
let secs:Int = time.seconds //And this would be 10
How would I do this using Swift 2 OS X (not iOS)

Something like this:
let temp:Int = Int(time + 0.5) // Rounding
let mins:Int = temp / 60
let secs:Int = temp % 60

This would be a relatively simple solution. It's worth noting this would truncate partial seconds. You'd have to use floating point math on the third line and call trunc()/ceil()/floor() on the result before conversion to an Int if you wanted control over that.
let time:Double = 70.149 //This can be any value
let mins:Int = Int(time) / 60 //In this case it would be 1
let secs:Int = Int(time - Double(mins * 60)) //And this would be 10

Swift 5
The date components formatter has lots of advantages when displaying human readable text to a user. This function will take a double.
func humanReadable(time:Double) -> String {
let formatter = DateComponentsFormatter()
formatter.allowedUnits = [.hour, .minute, .second]
formatter.unitsStyle = .full
if let str = formatter.string(from: time) {
return str
}
return "" // empty string if number fails
}
// will output '1 minute, 10 seconds' for 70.149

Related

Heartrate with no decimal places

Im doing a watch app for the Apple Watch in Xcode and the sample code from the Apple Developer site SpeedySloth: Creating a Workout has the HeartRate rounded to one decimal place, e.g. 61.0
How can I fix this?
case HKQuantityType.quantityType(forIdentifier: .heartRate):
/// - Tag: SetLabel
let heartRateUnit = HKUnit.count().unitDivided(by: HKUnit.minute())
let value = statistics.mostRecentQuantity()?.doubleValue(for: heartRateUnit)
let roundedValue = Double( round( 1 * value! ) / 1 )
label.setText("\(roundedValue) BPM")
I tried changing both the 1's in there to 0 but that gave me a 6.1 BPM or a 0.0 BPM
Thanks
A simple solution is to round to an integer and show the integer.
let value = // ... some Double ...
let s = String(Int(value.rounded(.toNearestOrAwayFromZero)))
label.setText(s + " BPM")
Properly, however, you should put formatting a string based on a number into the hands of a NumberFormatter. That's its job: to format a number.
let i = value.rounded(.toNearestOrAwayFromZero)
let nf = NumberFormatter()
nf.numberStyle = .none
let s = nf.string(from: i as NSNumber)!
// ... and now show the string

Solution time in CPLEX

I want to find the solution time of my model in CPLEX and I used the following code:
float temp;
execute{
var before = new Date();
temp = before.getTime();
}
// solve the model
execute{
var after = new Date();
writeln("solving time ~= ",after.getTime()-temp);
}
But the result is : 1.5592e+ 12, which is a huge number. So, do you know how can I reach to the the solution time in second or millisecond?
This is more of a pure javascript question rather than something related to CPLEX. The number you're getting is in milliseconds, but you can convert that into seconds, minutes, etc. using the techniques described at stackoverflow.com/questions/41632942. For example:
var timeDiff = after.getTime() - temp;
// Convert from milliseconds to seconds.
timeDiff /= 1000;
// Display diff in seconds.
writeln("solving time ~= ", timeDiff);

Can DateComponentsFormatter format fractional seconds?

I want to print, e.g., the value 1.5 as "1.5 sec", like Safari's timeline does, and I'm trying to use DateComponentsFormatter for it.
Unfortunately, its .allowedUnits only goes down to .second (even though the enum has .nanosecond). I tried setting .allowsFractionalUnits = true, but I'm still getting "0 sec".
Is there any way to get fractional seconds out of DateComponentsFormatter?
For positional units style, DateComponentsFormatter can be used together with NumberFormatter to get locale-aware string.
func format(_ seconds: TimeInterval) -> String {
let components = DateComponentsFormatter()
components.allowedUnits = [.minute, .second]
components.allowsFractionalUnits = true // does not work as expected
components.unitsStyle = .positional
components.zeroFormattingBehavior = .pad
let fraction = NumberFormatter()
fraction.maximumIntegerDigits = 0
fraction.minimumFractionDigits = 0
fraction.maximumFractionDigits = 3
fraction.alwaysShowsDecimalSeparator = false
let fractionalPart = NSNumber(value: seconds.truncatingRemainder(dividingBy: 1))
return components.string(from: seconds)! + fraction.string(from: fractionalPart)!
}
print(Locale.current) // ru_RU (current)
print(format(600.5)) // 10:00,5 <- note locale specific decimal separator
Unfortunately, using this method for other date styles is even more hacky.

Replacing NSDate value if two NSDate objects aren't equal

basically I'm writing an app and I want some of its values to update weekly - so, using NSDate and NSUserDefaults I currently have this scenario set out:
let userDefaults = NSUserDefaults.standardUserDefaults()
var startOfWeek: NSDate?
The above is global^
var referenceDate = NSDate.timeIntervalSinceReferenceDate()
while referenceDate > 604800 {
if referenceDate > 604800 {
referenceDate -= 604800
}
This basically takes the amount of seconds that have elapsed since the 1st of Jan 2001 and subtracts 604800, which is the amount of seconds in a week, until you have an amount of seconds that is less than a week. This amount of seconds is basically the amount of seconds into the week, you're in.
After this I then create a variable which is just the negative of how many seconds into the week we are, a variable which is the current time and use them to create a new date object which is the start point for the week:
var weekTimer: NSTimeInterval = (-referenceDate)
var startOfWeek = userDefaults.objectForKey("startOfWeekKey") as? NSDate
var currentTime = NSDate(timeIntervalSinceNow: 0)
if startOfWeek == nil {
startOfWeek = NSDate(timeInterval: weekTimer, sinceDate: currentTime)
userDefaults.objectForKey("startOfWeekKey")
}
else {
}
So basically it creates a value for the start of the week and saves it to NSUserDefaults under the key "startOfWeekKey" if the value doesn't already exist. If the value does already exist, because it's already been saved, it's happy with this value and nothing happens.
Now, we create a new value to compare to our startOfWeek value so we can test if we enter a new week.
var startOfWeekCheck = NSDate(timeInterval: weekTimer sinceDate: currentTime)
Now we compare them:
if startOfWeek! == startOfWeekCheck {
}
else {
println("New week begins") //update other, irrelevant stuff here
startOfWeek = startOfWeekCheck
}
No matter what, new week begins is always printed, I added the following line to check what was happening:
println("\(startOfWeek!) \(startOfWeekCheck)")
And it prints the same value to the logs
I'm pretty unsure what to do at this point. Did I mess up? Can you not compare the two date objects like that? Is this a ridicuously inefficient manner to create a way to reset/change something once a week?
Note, this is not the exact code, I typed this all by hand because the code is on my macbook and I'm on my desktop, so if there are any typos / w/e don't worry about it, no compile errors on my mac.
Thanks!
This looks way too complicated. There is no need to do all the date calculations yourself. Especially because you do them wrong. Not every week has 604800 seconds. In many timezones you have one week per year which has 601200 seconds, and one week which has 608400 seconds. Also known as Daylight saving time. There are even countries that skipped a whole day in one year.
You have to use NSCalendar and NSDateComponents for correct date calculations.
But I would do it completely different:
Save the next refresh date in NSUserDefaults (default to distantPast)
If today >= next refresh date: refresh & write new refresh date.
Something like this:
let calendar = NSCalendar.currentCalendar()
// If nextRefreshDate was never written by us (i.e. first start of app) it will containt distantPast, which is in year 1 or so
NSUserDefaults.standardUserDefaults().registerDefaults(["nextRefreshDate" : NSDate.distantPast()])
// since we registered a default value we will always receive a valid NSDate object, so we can force unwrap
let nextRefreshDate = NSUserDefaults.standardUserDefaults().objectForKey("nextRefreshDate") as NSDate
// equivalent to: (nextRefreshDate < today) || (nextRefreshDate == today)
if nextRefreshDate.compare(NSDate()) != NSComparisonResult.OrderedDescending {
println("Refresh")
let refreshSuccess = true // get from your internet download code
if refreshSuccess {
// don't save the next refresh date until the refresh was actually sucessful. This makes sure that we refresh on next launch if this refresh fails for some reason
var startOfCurrentWeek: NSDate?
if calendar.rangeOfUnit(.CalendarUnitWeekOfMonth, startDate: &startOfCurrentWeek, interval: nil, forDate: NSDate()) {
if let startOfCurrentWeek = startOfCurrentWeek {
if let startOfNextWeek = calendar.dateByAddingUnit(.CalendarUnitWeekOfMonth, value: 1, toDate: startOfCurrentWeek, options: nil) {
NSUserDefaults.standardUserDefaults().setObject(startOfNextWeek, forKey: "nextRefreshDate")
println("Next refresh scheduled for \(startOfNextWeek)")
}
}
}
}
}
else {
println("No refresh necessary. Next refresh scheduled for \(nextRefreshDate)")
}

How can I format time intervals in Cocoa?

I'm looking for a class that formats time intervals like this:
1 hour 3 minutes
2 hours 5 minutes 12 seconds
5 days 2 hours
Is there anything built-in or a library that supports this kind of time interval formatting?
I thought about doing it myself, but there are all sorts of problems:
Localization
Non-gregorian calendars.
An old question, but for anyone who stumbles on this, check out NSDateComponentsFormatter.
For example, here's a NSDate category method from my DejalFoundationCategories open source project:
+ (NSString *)dejal_relativeStringForTimeInterval:(NSTimeInterval)timeInterval style:(NSDateComponentsFormatterUnitsStyle)unitsStyle maximumUnits:(NSInteger)maximumUnits keepZero:(BOOL)keepZero defaultValue:(NSString *)defaultValue;
{
// If more than 10 years, assume distant past or future:
if (abs(timeInterval) > 60 * 60 * 24 * 365 * 10)
{
return defaultValue;
}
NSDateComponentsFormatter *formatter = [NSDateComponentsFormatter new];
formatter.unitsStyle = unitsStyle;
formatter.maximumUnitCount = maximumUnits;
if (keepZero)
{
formatter.zeroFormattingBehavior = NSDateComponentsFormatterZeroFormattingBehaviorDropLeading | NSDateComponentsFormatterZeroFormattingBehaviorDropMiddle;
}
else
{
formatter.zeroFormattingBehavior = NSDateComponentsFormatterZeroFormattingBehaviorDropAll;
}
return [formatter stringFromTimeInterval:timeInterval];
}

Resources