How to convert min to hours in swift3? - iphone

This is my JSON data
{
"service_facility_id": 1,
"service_id": 4,
"facility_name": "Fitting",
"charge_per_min": 40,
"charge_per_km": 50
},
{
"service_facility_id": 10,
"service_id": 4,
"facility_name": "Health Care",
"charge_per_min": 100,
"charge_per_km": 0
}
Currently i'm using Get method to print specific JSON output in X Code. So i managed to Minute(charge_per_min) value . But I want to display in a label in HH(Hours) format, so how to convert it minute to hours formate and disply into a uilabel..
The code as below.
if let con = country["charge_per_km"] as? Int {
print("+++++\(con) +++ ")
self.chargPerKm.append(con)
print(self.chargPerKm)
let encodedArray : NSData = NSKeyedArchiver.archivedData(withRootObject:self.chargPerKm) as NSData
//Saving
let defaults = UserDefaults.standard
defaults.setValue(encodedArray, forKey:"charge_per_km")
print("\(UserDefaults.standard.value(forKey: "charge_per_km")!)")
defaults.synchronize()
print(defaults)
}
any one help me.

try it in playground
func minutesToHoursAndMinutes(_ minutes: Int) -> (hours: Int , leftMinutes: Int) {
return (minutes / 60, (minutes % 60))
}
let tuple = minutesToHoursAndMinutes(100)
tuple.hours /// 1
tuple.leftMinutes /// 40

To convert from minutes to hours (could be replaced with any supported measurement values)
func calculateTime(_ timeValue: Float) -> String {
let timeMeasure = Measurement(value: Double(timeValue), unit: UnitDuration.minutes)
let hours = timeMeasure.converted(to: .hours)
if hours.value > 1 {
let minutes = timeMeasure.value.truncatingRemainder(dividingBy: 60)
return String(format: "%.f %# %.f %#", hours.value, "h", minutes, "min")
}
return String(format: "%.f %#", timeMeasure.value, "min")
}
As an example
let value = calculateTime(50) //50 min
let value1 = calculateTime(125) // 2 h 5 min

Related

How to convert a time pattern from a string to TimeInterval in Swift?

I have an array of strings that contains a time pattern (e.g '30 min'):
let arrayOfStrings: [String] = ["Episode 1 - 23 min", "Episode 2 - 42 min", "Episode 3 - 45 min"]
func convertToTimeInterval(from string: String) -> TimeInterval {
// logic here...
return timeInterval // Double
}
So using such a method, I want from the results:
arrayOfStrings.forEach { string in
print(convertToTimeInterval(from: string))
}
// Prints
1380 // timeinterval from "23 min"
2520 // timeinterval from "42 min"
2700 // timeinterval from "45 min"
I have tried splitting from the the 'min' character but the problem is that it has to support multiple language format. So there is no way to know in advance the character to split from.
I have also tried getting the CharacterSet.separatedBy but the string can contains multiple decimal that have nothing to do with the time (e.g Episode 1)
Thanks for your help!
A rather underestimated but powerful API in Objective-C and Swift is (NS)Scanner.
Assuming there is always a hyphen and a whitespace character before the duration value just scanUpTo "- " then scan the pattern and then scan the numeric value as Double and multiply it with 60.
func convertToTimeInterval(from string: String) -> TimeInterval? {
let scanner = Scanner(string: string)
scanner.scanUpToString("- ")
scanner.scanString("- ")
guard let duration = scanner.scanDouble() else { return nil }
return duration * 60.0
}
Or – a bit more elaborate – with NSRegularExpression. The pattern captures one or more digits after " - "
func convertToTimeInterval(from string: String) -> TimeInterval? {
let regex = try! NSRegularExpression(pattern: #"\s-\s(\d+)"#)
guard let firstMatch = regex.firstMatch(in: string, range: NSRange(string.startIndex..., in: string)) else { return nil }
let durationRange = Range(firstMatch.range(at: 1), in: string)!
return Double((string[durationRange]))! * 60.0
}
However it becomes more convenient with the new Regex API introduced in Swift 5.7
func convertToTimeInterval(from string: String) -> TimeInterval? {
let regex = Regex {
" - "
Capture { OneOrMore(.digit) } transform: {
Double($0)! * 60.0
}
}
return string.firstMatch(of: regex)?.output.1
}
you could try this approach, where each string in the array is
split into sections, and the minutes extracted and returned as a Double/TimeInterval.
This should (not tested) cater for multiple languages that uses Western Arabic numerals
let arrayOfStrings: [String] = ["Episode 1 - 23 min", "Episode 2 - 42 min", "Episode 3 - 45 min"]
arrayOfStrings.forEach { string in
let t = convertToTimeInterval(from: string)
print("--> timeInterval: \(t) minutes or \(t * 60) seconds")
}
func convertToTimeInterval(from string: String) -> TimeInterval {
if let last = string.split(separator: "-").last {
let term2 = last.split(separator: " ")
if let minutes = term2.first {
if let result = Double(minutes.trimmingCharacters(in: .whitespacesAndNewlines)) {
return result
}
}
}
return 0.0 // <-- adjust as desired
}

Formatting milliseconds with a Timer in Swift and SwiftUI

I have this function which can successfully convert a counter variable into a beautifully formatted minutes and seconds string. How can I extend this to a format displaying MM:SS:milliseconds ?
I thought perhaps to do let milliseconds = Int(Double(seconds / 60) * 100) and append it to the return. Any tips?
Note: my timer should be publishing with enough granularity #State var timer = Timer.publish(every: 0.1, on: .main, in: .common).autoconnect()
func formatMmSs(counter: Double) -> String {
let minutes = Int(counter) / 60 % 60
let seconds = Int(counter) % 60
return String(format: "%02i:%02i", minutes, seconds)
}
You just need to multiply your counter (number of seconds) times 1000,
truncating remainder dividing by 1000 and coerce the result to integer:
func formatMmSsMl(counter: Double) -> String {
let minutes = Int((counter/60).truncatingRemainder(dividingBy: 60))
let seconds = Int(counter.truncatingRemainder(dividingBy: 60))
let milliseconds = Int((counter*1000).truncatingRemainder(dividingBy: 1000))
return String(format: "%02d:%02d.%03d", minutes, seconds, milliseconds)
}
Or implemented as a computed property for BinaryFloatingPoint types:
extension BinaryFloatingPoint {
var intValue: Int { Int(self) }
var minutesSecondsMilliseconds: String {
String(format: "%02d:%02d.%03d",
(self / 60).truncatingRemainder(dividingBy: 60).intValue,
truncatingRemainder(dividingBy: 60).intValue,
(self * 1000).truncatingRemainder(dividingBy: 1000).intValue)
}
}
You can also custom format the floating point. No need to coerce to integer as follow:
extension TimeInterval {
var minutesSecondsMilliseconds: String {
String(format: "%02.0f:%02.0f.%03.0f",
(self / 60).truncatingRemainder(dividingBy: 60),
truncatingRemainder(dividingBy: 60),
(self * 1000).truncatingRemainder(dividingBy: 1000).rounded(.down))
}
}
123.45678.minutesSecondsMilliseconds // "02:03.456"
This is keep using your approach also following Leo approach,
func formatMmSs(counter: Double) -> String {
let minutes = Int(counter) / 60 % 60
let seconds = Int(counter) % 60
let milliseconds = Int(counter*1000) % 1000
return String(format: "%02d:%02d:%03d", minutes, seconds, milliseconds)
}

Calculate time difference from Int in Swift

I need to calculate the difference between two Int and format it to show hours, minutes. I can the function below to partially apart from the initial int difference.
Example: If i have a start Int of 0811 and then an end Int of 0912 the difference is 101. If I then take 12 from the result I should have 91. When I use the result to convert to time it returns 1 hour and 31 mins - which is correct. However I need to somehow convert it further up the chain and then take it off to format the time correctly. This should mean the 101 should be 1 hour 1 minute.
func calculateTimeDifference(start: Int, end: Int, longVersion: Bool) -> String {
let count = end - start
let total = minutesToHoursMinutes(minutes: count)
var formatted = ""
if total.hours != 0 {
formatted += "\(total.hours)"
let amount = total.hours > 1 ? " hours " : " hour "
formatted += amount
}
if total.leftMinutes != 0 {
formatted += "\(total.leftMinutes)"
let amount = total.leftMinutes > 1 ? " minutes " : " minute "
formatted += amount
}
return String(describing: formatted)
}
func minutesToHoursMinutes(minutes : Int) -> (hours : Int, leftMinutes : Int) {
return (minutes / 60, (minutes % 60))
}
You shouldn't calculate the difference between two times expressed in Ints by subtracting them. Use the proper Date API.
Here, I converted the Ints to strings first and then parsed them using a date formatter. After that timeIntervalSince can tell you the difference in seconds. You just need some modulus and division to get the hours and minutes from that:
func calculateTimeDifference(start: Int, end: Int) -> String {
let formatter = DateFormatter()
formatter.dateFormat = "HHmm"
var startString = "\(start)"
if startString.characters.count < 4 {
for _ in 0..<(4 - startString.characters.count) {
startString = "0" + startString
}
}
var endString = "\(end)"
if endString.characters.count < 4 {
for _ in 0..<(4 - endString.characters.count) {
endString = "0" + endString
}
}
let startDate = formatter.date(from: startString)!
let endDate = formatter.date(from: endString)!
let difference = endDate.timeIntervalSince(startDate)
return "\(Int(difference) / 3600)Hr \(Int(difference) % 3600 / 60)Min"
}
Inherintly you are approaching this from a strange angle and causing yourself issues.
Instead of Int, which is inappropriate for storing a time, use TimeInterval which can hold a full date information, e.g.:
let second:TimeInterval = 1.0
let minute:TimeInterval = 60.0
let hour:TimeInterval = 60.0 * minute
let day:TimeInterval = 24 * hour
Then when you want to determine the time difference between two times it's very basic arithmetic.
SWIFT 4
In Swift 4 characters is deprecated, so Sweepers solution in Swift 4 is
func calculateTimeDifference(start: Int, end: Int) -> String {
let formatter = DateFormatter()
formatter.dateFormat = "HHmm"
var startString = "\(start)"
if startString.count < 4 {
for _ in 0..<(4 - startString.count) {
startString = "0" + startString
}
}
var endString = "\(end)"
if endString.count < 4 {
for _ in 0..<(4 - endString.count) {
endString = "0" + endString
}
}
let startDate = formatter.date(from: startString)!
let endDate = formatter.date(from: endString)!
let difference = endDate.timeIntervalSince(startDate)
return "\(Int(difference) / 3600)Hr \(Int(difference) % 3600 / 60)Min"
}

Substring from range of two characters

Im trying to convert a time displaying string to a Int.
The syntax looks like this and i want to extract the integers and multiply the first and add the later to get the time in minutes.
12h 10m
3h 14m
16h 0m
Since the displayed string can be either hhmm, hmm, hhm or hm I cant substring with a fixed offset.
I'm trying to substring the string by first finding the " " and then the m.
In other languages this would be easy but for some reson I cant get it to work in swift.
Please help me, you're my only hope.
You can get your time components (hour and minutes) using components(separated:) and get the first component (hour), multiply it by 60 and add the last component (minutes) to it.
extension String {
var minutes: Int {
var minutes = 0
if let hourChars = components(separatedBy: " ").first?.characters.dropLast(),
let hours = Int(String(hourChars)) {
minutes += hours * 60
}
if let minChars = components(separatedBy: " ").last?.characters.dropLast(),
let mins = Int(String(minChars)) {
minutes += mins
}
return minutes
}
}
Testing
let str1 = "12h 10m"
let minutes1 = str1.minutes // 730
let str2 = "3h 14m"
let minutes2 = str2.minutes // 194
let str3 = "16h 0m"
let minutes3 = str3.minutes // 960
i think in your case it's better to spilt the string that you have twice
let string = "12h 10m 3h 14m 16h 0m"
var array = string.characters.split(separator: "h").map(String.init)
var result: [String] = []
array.forEach {
result.append(contentsOf: $0.characters.split(separator: "m").map(String.init))
}
// ["12", " 10", " 3", " 14", " 16", " 0"]
print(result)
Since you need to manipulate with date/time strings only I think you should better use a build-in DateFormatter for doing it
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "HH'h' mm'm'"
let date = dateFormatter.date(from: "2h 10m")!
let hour = Calendar.current.component(.hour, from: date)
// returns 2
let minutes = Calendar.current.component(.minute, from: date)
// returns 10
best solution for your question is
func getTime(time:String)->(Int,Int)
{
let arry = time.components(separatedBy: " ")
let hours = arry[0]
let min = arry[1]
let indexForHour = hours.index(hours.startIndex, offsetBy: (hours.characters.count - 1))
let indexForMin = min.index(min.startIndex, offsetBy: (min.characters.count - 1))
let hour = Int(hours.substring(to: indexForHour))
let minut = Int(min.substring(to: indexForMin))
return (hour!,minut!)
}
let str1 = "12h 10m"
let str2 = "3h 14m"
let str3 = "16h 0m"
let firstTime:(hour:Int,min:Int) = getTime(time:str1)
print(firstTime)
let secondTime:(hour:Int,min:Int) = getTime(time:str2)
print(secondTime)
let thirdTime:(hour:Int,min:Int) = getTime(time:str3)
print(thirdTime)
OUTPUT
(hour: 12, min: 10)
(hour: 3, min: 14)
(hour: 16, min: 0)

More Functional / Swift way to convert time to minutes

I'm trying to convert a length of time in "Hours:Minutes" to "minutes". Time is given as a String, and I want to return a Double of minutes.
Currently I'm using the following function:
func convertMinHoursToDouble(length: String) -> Double {
var hours = 0.0
var minutes = 0.0
let lengthCleaned = length.stringByReplacingOccurrencesOfString(":", withString: "")
var count = 0
for char in lengthCleaned.characters {
if count == 0 {
hours = Double("\(char)")! * 60
} else if count == 1 {
minutes = Double("\(char)")! * 10
} else if count == 2 {
minutes = Double("\(char)")! + minutes
}
++count
}
return hours+minutes
}
let time = "2:16"
let convertedTime = convertMinHoursToDouble(time)
print(convertedTime) // prints 136.0
This works, however I'm trying to do this in a more functional / Swift way. How can it be done with the reduce function. This is the closest I can get to the solution.
let convertedTime = time.characters.reduce(0) { (dub, char) in dub + Double(String(char))! }
The pure Swift way would be :
let time = "02:16"
let converted = time.characters.split(":")
.flatMap { Int(String($0)) }
.reduce(0) { $0 * 60 + $1 }
print(converted) //"136\n"
Functional solution:
func convertMinHoursToDouble(time: String) -> Int {
let timeComps = (time as NSString).componentsSeparatedByString(":") as [NSString]
return timeComps.reduce(0) { acc, item in
acc * 60 + item.integerValue
}
}
let time = "02:15"
let convertedTime = convertMinHoursToDouble(time)
print(convertedTime)
You split the string into components, and reduce on that array. This works like a charm also for strings like "03:24:34" for which it computes the time in seconds.
You can add additional validation logic if you want to deal with malformed strings: no ":", more than one ":", invalid minutes value (e.g. 78), etc.