operation with hours using swift, sum and difference

Viewed 98

On my project I need to work with hours and min. I can't find to much info online.

here my issue:

let time1 = "22:00"
let time2 = "20:00"

Question 1:

how do I subtract the time1 - time2 ? I'm expecting result = 02:00 h

i start writing some code, converting this time to date..

let formatter = DateFormatter()
formatter.dateFormat = "HH:mm"
var time1d = formatter.date(from: time1)!
let time2d = formatter.date(from: time2)!

but now how do I subtract this two hours?

Question 2:

let time1 = "22:00"
let time2 = "20:00"

How do i sum time1 + time2 ? for example should give me result 42:00 hours

thanks for the help

2 Answers

This is not a Date. If you are only gonna work with hours and minutes and the input will always be a string properly formatted you should struct your data.

Create a Time structure

struct Time {
    let hour: Int
    let minute: Int
}

And a custom initializer. This assumes your string is always properly formatted 00:00:

extension Time {
    init?(string: String) {
        guard string.count == 5,
              Array(string)[2] == ":",
              let hour = Int(string.prefix(2)),
              let minute = Int(string.suffix(2)),
              0...59 ~= minute else {
            return nil
        }
        self.hour = hour
        self.minute = minute
    }
}

For displaying your Time struct property you can conform it to CustomStringConvertible and provide a custom description

extension Time: CustomStringConvertible {
    var description: String {
        String(format: "%02d:%02d", hour, minute)
    }
}

Regarding adding and subtracting you can make your Time struct conform to AdditiveArithmetic and implement the required operators:

extension Time: AdditiveArithmetic {
    static func - (lhs: Time, rhs: Time) -> Time {
        let minutes = lhs.minute - rhs.minute + lhs.hour * 60 - rhs.hour * 60
        return .init(hour: minutes/60, minute: minutes%60)
    }
    static func + (lhs: Time, rhs: Time) -> Time {
        let minutes = lhs.minute + rhs.minute + lhs.hour * 60 + rhs.hour * 60
        return .init(hour: minutes/60, minute: minutes%60)
    }
    static var zero: Time { .init(hour: 0, minute: 0) }
}

Playground testing:

let time1 = Time(string: "22:00")!
let time2 = Time(string: "20:00")!
let time3 = time1-time2
print(time3)
let time4 = time1+time2
print(time4)

Those will print

02:00
42:00

First we create the calculateDifference function which uses dateComponents function provided by Swift.

let time1 = "22:00"
let time2 = "20:00"

func formattedTime(_ time: String) -> Date? {
    let formatter = DateFormatter()
    formatter.locale = Locale(identifier: "en_US_POSIX")
    formatter.dateFormat = "HH:mm"
    return formatter.date(from: time)
}

func calculateDifference(_ from: String, _ to: String) -> (hour: Int, minutes: Int) {
    guard let fromTime = formattedTime(from),
          let toTime = formattedTime(to) else {
        return (0,0)
    }
    let calendar = Calendar.current
    
    let components = calendar.dateComponents([.hour, .minute], from: fromTime, to: toTime)
    return (components.hour ?? 0, components.minute ?? 0)
}

Then we create the calculateSum which uses the calculateDifference internally to get the hours by supplying the default hour as 00:00

func calculateSum(_ time1: String, _ time2: String) -> (hour: Int, minutes: Int) {
    let defaultTime = "00:00"
    let calculatedTime1 = calculateDifference(defaultTime, time1)
    let calcaultedTime2 = calculateDifference(defaultTime, time2)
    return(calculatedTime1.hour + calcaultedTime2.hour,
           calculatedTime1.minutes + calcaultedTime2.minutes)
}

Now if we run the below, we get the required results. Of course, some formatting will be required.

let difference = calculateDifference(time2, time1)
print("\(difference.hour):\(difference.minutes)")

let sum = calculateSum(time1, time2)
print("\(sum.hour):\(sum.minutes)")
Related