Get 12h hours am/pm Time - swift

I want to display the time from a Slider to a Label. So i must convert the value and get the current day time on it like 00:00 am/pm.
So i need there a stepper how print all 5 steps like (5,10,15,20,25....50,55)
So this code on the bottom don´t run good, have anybody a better way to make that ?
I have try it but it becomes an error when i slider back (zb: when it´s 8:00 am and i slider back to 7:55 am it come for first 7:00 am.
Here is the code:
func valueChange(_ sender: CircleSlider) {
let countmin = Int(Double(sender.value) * 14.4)
var hour = countmin / 60
let mins = countmin - (hour*60)
if hour >= 12 {
hour -= 12
Am.text = "Pm"
} else {
Am.text = "Am"
}
hours = hour
let i = String(mins)
switch i {
case "Nil":
minutes = 00
case "0":
minutes = 00
case "5":
minutes = 05
case "10":
minutes = 10
case "15":
minutes = 15
case "25":
minutes = 25
case "30":
minutes = 30
case "35":
minutes = 35
case "40":
minutes = 40
case "45":
minutes = 45
case "50":
minutes = 50
case "55":
minutes = 55
case "60":
minutes = 60
default:
break
}
self.circleTime.text = "\(String(format: "%02d", hours!)):\(String(format: "%02d", minutes!))"
}
Thank´s for Help :)

I think there's an issue in your method for 7:56, 7:57, 7:58, 7:59 (it is not truncating well). This code should work for you:
func valueChange(_ sender: CircleSlider) {
let countmin = Int(Double(sender.value) * 14.4)
var hour = countmin / 60
let mins = countmin - (hour * 60)
if hour >= 12 {
hour -= 12
Am = "Pm"
} else {
Am = "Am"
}
hours = hour
minutes = roundToFives(Double(mins))
// This fixes when you have hh:60. For instance, it fixes 7:60 to 8:00
if minutes == 60 {
hours = hour + 1
minutes = 0
}
self.circleTime.text = "\(String(format: "%02d", hours!)):\(String(format: "%02d", minutes!))"
}
// idea of this method comes from: http://stackoverflow.com/questions/27922406/round-double-to-closest-10-swift
private func roundToFives(x : Double) -> Int {
return 5 * Int(round(x / 5.0))
}

Related

Convert decimal time to hours and minutes in Swift

I am new to programming and this is my first program and question. I'm trying to write a function which will simply convert decimal time to Hours & Minutes. I'm removing the hours and multiplying the decimal minutes by 60 and adding the two back together as a string. I need to use this facility a couple of times in my program hence the function. The calculation which uses this function is straightforward but I'm getting odd results. If I maintain 'plannedStartFuel' as 450 and adjust 'minLandAllowance' I get the following results,
185 returns 1:28
182 returns 1:29
181 returns 1:30
180 returns 2:30
179 returns 2:30
175 returns 2:32
The correct answers are the 1:00 figures. I don't understand why the program seems to add an hour to the results at the 180 point. I'm sure there are are far better ways of completing this calculation than I've used, but if you can help I'd be grateful to know which part is causing the error and why. What have I tried?...everything! If you pitch your answer at a 7 year old I may have a chance of understanding. Thank you.
import UIKit
import Foundation
func decimalHoursConv (hours : Double) -> (_hrs:String, mins:String) {
let remainder = hours.truncatingRemainder(dividingBy: 1) * 60
let mins = (String(format: "%.0f", remainder))
let hrs = (String(format: "%.0f", hours))
return (hrs, mins)
}
var plannedStartFuel = Double (0)
var minLandAllowance = Double (0)
var flyingTimeToMLA = Double(0)
plannedStartFuel = 450
minLandAllowance = 180
flyingTimeToMLA = ((plannedStartFuel - minLandAllowance) / 3)/60
let MLAtime = (decimalHoursConv(hours: flyingTimeToMLA))
print ("Flight Time To MLA =", MLAtime.0,"hrs",MLAtime.1,"mins")
I might advise not bothering to calculate hours and minutes at all, but rather let DateComponentsFormatter do this, creating the final string for you.
For example:
let formatter: DateComponentsFormatter = {
let formatter = DateComponentsFormatter()
formatter.unitsStyle = .full
formatter.allowedUnits = [.hour, .minute]
return formatter
}()
Then supply this formatter the elapsed time measured in seconds (a TimeInterval, which is just an alias for Double):
let remaining: TimeInterval = 90 * 60 // e.g. 90 minutes represented in seconds
if let result = formatter.string(from: remaining) {
print(result)
}
On a English speaking device, that will produce:
1 hour, 30 minutes
The virtue of this approach is that not only does it get you out of the business of manually calculating hours and minutes yourself, but also that the result is easily localized. So, if and when you get around to localizing your app, this string will be localized automatically for you, too, with no further work on your part. For example, if you add German to your app localizations, then the US user will still see the above, but on a German device, it will produce:
1 Stunde und 30 Minuten
If you want it to say how much time is remaining, set includesTimeRemainingPhrase:
let formatter: DateComponentsFormatter = {
let formatter = DateComponentsFormatter()
formatter.unitsStyle = .full
formatter.includesTimeRemainingPhrase = true
formatter.allowedUnits = [.hour, .minute]
return formatter
}()
That will produce:
1 hour, 30 minutes remaining
If you want a “hh:mm” sort of representation:
let formatter: DateComponentsFormatter = {
let formatter = DateComponentsFormatter()
formatter.unitsStyle = .positional
formatter.zeroFormattingBehavior = .pad
formatter.allowedUnits = [.hour, .minute]
return formatter
}()
Will produce:
01:30
Bottom line, if you really want to calculate minutes and seconds, feel free, but if it’s solely to create a string representation, let the DateComponentFormatter do this for you.
EDIT
I realize you wanted to know what did not work with your method.
It's a matter of rounding, try roundind hours before passing it to String(format:) :
func decimalHoursConv (hours : Double) -> (_hrs:String, mins:String) {
let remainder = hours.truncatingRemainder(dividingBy: 1) * 60
let mins = (String(format: "%.0f", remainder))
let hours = hours.rounded(.towardZero)
let hrs = (String(format: "%.0f", hours))
return (hrs, mins)
}
it gives :
var value = (450.0-185.0)/3
decimalHoursConv(hours: value/60) // (_hrs "1", mins "28")
value = (450.0-182.0)/3
decimalHoursConv(hours: value/60) // (_hrs "1", mins "29")
value = (450.0-181.0)/3
decimalHoursConv(hours: value/60) // (_hrs "1", mins "30")
value = (450.0-180.0)/3
decimalHoursConv(hours: value/60) // (_hrs "1", mins "30")
value = (450.0-179.0)/3
decimalHoursConv(hours: value/60) // (_hrs "1", mins "30")
value = (450.0-175.0)/3
decimalHoursConv(hours: value/60) // (_hrs "1", mins "32")
BUT Still
If you're using Swift you should use Measurement
func convertToHoursAndMinutes(_ value: Double) -> DateComponents {
let unitMeasurement = Measurement(value: value, unit: UnitDuration.minutes)
let hours = unitMeasurement.converted(to: .hours).value
let decimalPart = hours.truncatingRemainder(dividingBy: 1)
let decimalPartMeasurement = Measurement(value: decimalPart, unit: UnitDuration.hours)
let decimalPartMeasurementInMinutes = decimalPartMeasurement.converted(to: .minutes)
let minutes = decimalPartMeasurementInMinutes.value.rounded(.toNearestOrEven)
return DateComponents(hour: Int(hours), minute: Int(minutes))
}
usage :
var value = (450.0-185.0)/3 // 88.33333333333333
convertToHoursAndMinutes(value) // hour: 1 minute: 28 isLeapMonth: false
value = (450.0-182.0)/3 // 89.33333333333333
convertToHoursAndMinutes(value) // hour: 1 minute: 29 isLeapMonth: false
value = (450.0-181.0)/3 // 89.66666666666667
convertToHoursAndMinutes(value) // hour: 1 minute: 30 isLeapMonth: false
value = (450.0-180.0)/3 // 90
convertToHoursAndMinutes(value) // hour: 1 minute: 30 isLeapMonth: false
value = (450.0-179.0)/3 // 90.33333333333333
convertToHoursAndMinutes(value) // hour: 1 minute: 30 isLeapMonth: false
value = (450.0-175.0)/3 // 91.66666666666667
convertToHoursAndMinutes(value) // hour: 1 minute: 32 isLeapMonth: false
Note that you can always use a tuple instead of DateComponents if you prefer.
String formatter rounds up.
You can use .rounded(.down) on Doubles to round them down. (or with other rules you need)
let number = (179.0/60.0) // 2.983333333333333
String(format: "%.0f", number) // returns 3
number.rounded(.up) // returns 3
number.rounded(.down) // returns 2
First you should structure your data. Next you don't need to format your value as a Double if you are not gonna display fractions. So you can simply convert your double to integer.
struct FlightPlan {
let plannedStartFuel: Double
let minimumLandAllowance: Double
}
extension FlightPlan {
var mlaTime: (hours: Int, minutes: Int) {
let hours = (plannedStartFuel - minimumLandAllowance) / 180
return (Int(hours), Int(modf(hours).1 * 60))
}
}
And you should use DateComponentsFormatter when displaying time to the user:
extension Formatter {
static let time: DateComponentsFormatter = {
let formatter = DateComponentsFormatter()
formatter.calendar?.locale = .init(identifier: "en_US_POSIX")
formatter.unitsStyle = .brief
formatter.allowedUnits = [.hour,.minute]
return formatter
}()
}
extension FlightPlan {
var mlaTimeDescrition: String {
return "Flight Time To MLA = " + Formatter.time.string(from: .init(hour: mlaTime.hours, minute: mlaTime.minutes))!
}
}
let flightPlan = FlightPlan(plannedStartFuel: 450,
minimumLandAllowance: 180)
flightPlan.mlaTime // (hours 1, minutes 30)
flightPlan.mlaTime.hours // 1
flightPlan.mlaTime.minutes // 30
flightPlan.mlaTimeDescrition // "Flight Time To MLA = 1hr 30min"

MInutes and seconds with 2 digits

I have an input in seconds I store it in a var:
var totalTime = 60
I want to show it with 2 digits for minutes and 2 digits for seconds:
01:00
What I have tried:
let minutes = String(totalTime / 60)
let seconds = String(totalTime % 60)
label.text = minutes + ":" + seconds
This gives me: 1:0
But I want 01:00
I tried and It does not work:
label.text = String(format: "%02d:%02d", minutes, seconds)
The problem with your second approach is that it expects an integer and you are passing a string.
let minutes = totalTime / 60
let seconds = totalTime % 60
label.text = String(format: "%02d:%02d", minutes, seconds)

Trying to calculate time difference, but am receiving negative answer

I am trying to calculate the time difference (x hrs x mins) between two timings, the current time, and the time set by user with the timepicker.
I would receive a negative value, e.g. -7 hrs 30 mins.
To solve this, I've read that i will need to include if statement. However, i receive the following error and am unable to solve it:
"Cannot convert value of type 'Date' to expected argument type 'TimeInterval' (aka 'Double')"
would greatly appreciate some help, thanks!
func findTimeDiff() {
let time1 = currentTimeOutlet
let time2 = alarmTimeOutlet
let formatter = DateFormatter()
formatter.dateFormat = "hh:mma"
let date1 = formatter.date(from: time1!.text!)
let date2 = formatter.date(from: time2!.text!)
var elapsedTime = date2!.timeIntervalSince(date1!)
let hours = floor(elapsedTime / 60 / 60)
let minutes = floor((elapsedTime - (hours * 60 * 60)) / 60)
if (date2!) < (date1!) {
var elapsedTime = ((date2! + 86400000) - date1!)
let hours = floor(elapsedTime / 60 / 60)
let minutes = floor((elapsedTime - (hours * 60 * 60)) / 60)
timeDiffOutlet.text = ("\(Int(hours)) hr and \(Int(minutes)) min")
}
else {
var elapsedTime = date2!.timeIntervalSince(date1!)
let hours = floor(elapsedTime / 60 / 60)
let minutes = floor((elapsedTime - (hours * 60 * 60)) / 60)
timeDiffOutlet.text = ("\(Int(hours)) hr and \(Int(minutes)) min")
}
}
You should avoid performing calculations with hard coded values like this where dates and times are concerns. Instead it's much better to use the methods provided for you by the Calendar class.
So something like this:
func findTimeDiff2() {
let time1 = currentTimeOutlet
let time2 = alarmTimeOutlet
let formatter = DateFormatter()
formatter.dateFormat = "hh:mma"
let date1 = formatter.date(from: time1!.text!)
let date2 = formatter.date(from: time2!.text!)
let components = Calendar.current.dateComponents([.hour, .minute], from: date1!, to: date2!)
timeDiffOutlet.text = "\(abs(components.hour!)) hr and \(abs(components.minute!)) min"
}
Doing this means that situations such as daylight saving time will be handled for you although in this case as you don't know the day on which the alarm is taking place you won't be able to know if daylight saving applies or not. It would really be better to use a full date instead of just the time.
Why are you trying completely different expression in case of (date2!) < (date1!) ?
Try changing this line:
var elapsedTime = ((date2! + 86400000) - date1!)
To:
var elapsedTime = date1!.timeIntervalSince(date2!)

Calculate average pace

I need to convert a decimal hour in to hh:mm:ss to display as average pace for a walking app.
I have converted the time to decimal and I have calculated the pace in to decimal however I am unsure how to convert this to time.
My timeDecimal is:
let timeDecimal:Double = (hourSource + (minuteSource / 60) + (secondSource / 3600)) / distanceSource
which gives me something like 0.4375
0 = 0
.4375 * 60 = 26.25
.25 = * 60 = 15
I know the time should be 00:26:15 but not sure the formula to achieve this without splitting up the result and performing the multiplication multiple times.
Any help is appreciated.
let formatter = NSDateComponentsFormatter()
formatter.allowedUnits = [ .Hour, .Minute, .Second ]
formatter.unitsStyle = .Positional
formatter.zeroFormattingBehavior = .Pad
let string = formatter.stringFromTimeInterval(0.4375 * 3600)!
Result: 0:26:15.
Try
var mytime = timeDecimal * 60
var minutes = floor(mytime)
var seconds = (mytime - minutes) * 60
func timeStringFrom(time time: Int) -> String {
let HoursLeft = time/3600
let MinutesLeft = (time%3600)/60
let SecondsLeft = (((time%3600)%60)%60)
if HoursLeft == 0 {
return String(format:"%.2d:%.2d", MinutesLeft, SecondsLeft)
} else {
return String(format:"%2d:%.2d:%.2d", HoursLeft, MinutesLeft, SecondsLeft)
}
}
Note: I'll probably turn it into a generic function soon

AVAudioPlayer currentTime exceeds duration

I'm making my own audio player using AVAudioPlayer.
NOTE: "p" is my instance of the player
Here's how I'm reading the track progress in one of the labels:
currentTime.text = [NSString stringWithFormat:#"%d:%02d", (int)p.currentTime / 60, (int)p.currentTime % 60];
Here's how I set the total duration of the track in one of the labels:
int seconds = (int)p.duration % 60;
int minutes = (int)p.duration / 60;
duration.text = [NSString stringWithFormat:#"%d:%02d", minutes, seconds];
When I run the app on the device, the track's current time ALWAYS exceeds the duration (by about 5-10 seconds).
Is this a bug in AVAudioPlayer, or am I not doing it correctly?
NOTE: This behavior also occurs on the device (not just on the simulator)
After finding the seconds by using % 60, you should remove those seconds when converting the remaining for the minutes. For e.g., with the total duration of 119 seconds after finding 59 seconds you should remove that from 119 and then do minute conversion for 60 seconds (119-59). That might solve your problem.
Minutes should be float: 152 seconds / 60.0f = 2.5333 not 2.
That being said, if you want to show the remaining minutes without the seconds you already obtain: int minutes = (p.duration-seconds) / 60
Also, for a better method to format time the way you want to, have a look at the second answer in this question (not the accepted solution).
Here is the function:
func setTimeString(duration: Double)->String {
var audioDurationSeconds = duration
var expression = ""
var minutesString = "00"
var minutesFloat = 0.0
if (audioDurationSeconds)/60 >= 1 {
minutesFloat = (audioDurationSeconds) / 60
audioDurationSeconds = TimeInterval(Int(audioDurationSeconds)%60)
if minutesFloat < 10.0 {
minutesString = String.init(format: "0%.f", floor(minutesFloat))
} else {
minutesString = String.init(format: "%.f", floor(minutesFloat))
}
}
if audioDurationSeconds < 10.0 {
expression = String.init(format: "%#:0%i", minutesString, Int(audioDurationSeconds))
} else {
expression = String.init(format: "%#:%i", minutesString, (Int(audioDurationSeconds)))
}
return expression
}
extension UILabel{
func getTimeString(from duration:Double) -> String{
let hours = Int(duration / 3600)
let minutes = Int(duration / 60) % 60
let seconds = Int(duration.truncatingRemainder(dividingBy: 60))
if hours > 0 {
return String(format: "%i:%02i:%02i", arguments: [hours,minutes,seconds])
}else {
return String(format: "%02i:%02i", arguments: [minutes,seconds])
}
}