Usama bin Attique
Usama bin Attique

Reputation: 337

Adding Time Interval. e.g hours, minutes and seconds

I am getting time from the response in hours, minutes and seconds like "01:32:34" of multiple objects. I have saved it in a custom date object, where i am saving the date value and the string value, there are a large number of records so i am saving it in my local db and upon retrieving i get the date value in the format 1999-12-31 19:01:04 +0000 whereas my string value which i am getting from response as well is 19:01:04. now i would like to add all of these values to return a string e.g 1:15:16, 00:15:02, 00:45:27 should return 2 hours 15 minutes 45 seconds. I have explored Calendar.Components.byAdding but the methods there only let me add one single component, it doesn't receive an array and return Date. Is there any swifty way to achieve this, I want to achieve this via an elegant and proper method, i could think of a few fixes but they don't seem appropriate.

Upvotes: 0

Views: 2120

Answers (1)

Rob
Rob

Reputation: 437442

I’m going to assume that “01:32:34” represents an elapsed time of 5,554 seconds, not 1:32am. So, I’d convert it to a TimeInterval, not a Date:

func timeInterval(from string: String) -> TimeInterval? {
    let components = string.components(separatedBy: ":").map { Double($0) }
    guard 
        components.count == 3,
        let hours = components[0],
        let minutes = components[1],
        let seconds = components[2]
    else { return nil }

    return ((hours * 60) + minutes) * 60 + seconds
}

You can chose to store either the original “01:32:34” string or this value, 5,554.0.

Anyway, then adding these numeric time intervals is trivial addition. And to display a resulting TimeInterval, you’d use a DateComponentsFormatter, e.g.

let timeIntervalFormatter: DateComponentsFormatter = {
    let formatter = DateComponentsFormatter()
    formatter.unitsStyle = .positional
    formatter.allowedUnits = [.hour, .minute, .second]
    return formatter
}()

func totalElapsed(_ strings: [String]) -> String? {
    let total = strings.reduce(TimeInterval.zero) { sum, string in
        sum + (timeInterval(from: string) ?? 0)
    }
    return timeIntervalFormatter.string(from: total)
}

let strings = ["1:15:16", "00:15:02", "00:45:27"]

let result = totalElapsed(strings)

02:15:45

Or if you want more of a (localized) natural language representation, use unitsStyle of .full:

2 hours, 15 minutes, 45 seconds

This approach (using TimeInterval, not Date) has the virtue that it also can represent intervals that exceed 24 hours.

Upvotes: 2

Related Questions