218

I have a (somewhat?) basic question regarding time conversions in Swift.

I have an integer that I would like converted into Hours / Minutes / Seconds.

Example: Int = 27005 would give me:

7 Hours 30 Minutes 5 Seconds 

I know how to do this in PHP, but alas, swift isn't PHP.

0

25 Answers 25

409

Define

func secondsToHoursMinutesSeconds(_ seconds: Int) -> (Int, Int, Int) { return (seconds / 3600, (seconds % 3600) / 60, (seconds % 3600) % 60) } 

Use

> secondsToHoursMinutesSeconds(27005) (7,30,5) 

or

let (h,m,s) = secondsToHoursMinutesSeconds(27005) 

The above function makes use of Swift tuples to return three values at once. You destructure the tuple using the let (var, ...) syntax or can access individual tuple members, if need be.

If you actually need to print it out with the words Hours etc then use something like this:

func printSecondsToHoursMinutesSeconds(_ seconds: Int) { let (h, m, s) = secondsToHoursMinutesSeconds(seconds) print ("\(h) Hours, \(m) Minutes, \(s) Seconds") } 

Note that the above implementation of secondsToHoursMinutesSeconds() works for Int arguments. If you want a Double version you'll need to decide what the return values are - could be (Int, Int, Double) or could be (Double, Double, Double). You could try something like:

func secondsToHoursMinutesSeconds(seconds: Double) -> (Double, Double, Double) { let (hr, minf) = modf(seconds / 3600) let (min, secf) = modf(60 * minf) return (hr, min, 60 * secf) } 
Sign up to request clarification or add additional context in comments.

5 Comments

The last value (seconds % 3600) % 60 can be optimized to seconds % 60. No need to extract the hours first.
@GoZoner - i can't seem to be getting the printSecondsToHoursMinutesSeconds function to be working properly. This is what I have in a playground, but printSecondsToHoursMinutesSeconds isnt returning anything: import UIKit func secondsToHoursMinutesSeconds (seconds : Int) -> (Int, Int, Int) { return (seconds / 3600, (seconds % 3600) / 60, (seconds % 3600) % 60) } let (h,m,s) = secondsToHoursMinutesSeconds(27005) func printSecondsToHoursMinutesSeconds (seconds:Int) -> () { let (h, m, s) = secondsToHoursMinutesSeconds (seconds) println ("(h) Hours, (m) Minutes, (s) Seconds") }
printSecondstoHoursMinutesSeconds() doesn't return anything (see the -> () return type in the function declaration). The function prints something; which does not show up in a Playground. If you want it to return something, say a String then eliminate the println() call and fix the function's return type.
@GoZoner - just a quick question in your syntax above. How would I declare that 27005 in a variable? I'm working on a tool right now to get my feet wet with swift. I have a constant that displays the amount of seconds (generated after my basic calculations). let cocSeconds = cocMinutes * 60. (cocSeconds is what I want to use in place of 27005.) I think the problem I am having is cocSeconds is a double, and in your syntax, you're using Ints. How would I go about adjusting this code to put a variable in place of 27005? Thank you so much in advance!!!
The solution I gave works for Int types because of the nature of the / and % functions. That is / drops the factional part. The same code won't work for Double. Specifically 2 == 13/5 but 2.6 == 13.0/5. Therefore you would need a different implementation for Double. I've updated my answer with a note on this.
291

In macOS 10.10+ / iOS 8.0+ (NS)DateComponentsFormatter has been introduced to create a readable string.

It considers the user's locale und language.

let interval = 27005 let formatter = DateComponentsFormatter() formatter.allowedUnits = [.hour, .minute, .second] formatter.unitsStyle = .full let formattedString = formatter.string(from: TimeInterval(interval))! print(formattedString) 

The available unit styles are positional, abbreviated, short, full, spellOut and brief.

For more information please read the documenation.

6 Comments

Using formatter.unitsStyle = .positional gives exactly what I want (which is 7:30:05)! Best answer IMO
And you can add the zero ``` formatter.zeroFormattingBehavior = .pad ```
How to get the vice versa of this. That is how to convert Hour , Minute to seconds
@AngelFSyrus Simply hours * 3600 + minutes * 60
You might ned this if your seconds are giving less than a minute, especially in the shorter styles : formatter.zeroFormattingBehavior = [ .pad ]
|
125

Building upon Vadian's answer, I wrote an extension that takes a Double (of which TimeInterval is a type alias) and spits out a string formatted as time.

extension Double { func asString(style: DateComponentsFormatter.UnitsStyle) -> String { let formatter = DateComponentsFormatter() formatter.allowedUnits = [.hour, .minute, .second, .nanosecond] formatter.unitsStyle = style return formatter.string(from: self) ?? "" } } 

Here are what the various DateComponentsFormatter.UnitsStyle options look like:

10000.asString(style: .positional) // 2:46:40 10000.asString(style: .abbreviated) // 2h 46m 40s 10000.asString(style: .short) // 2 hr, 46 min, 40 sec 10000.asString(style: .full) // 2 hours, 46 minutes, 40 seconds 10000.asString(style: .spellOut) // two hours, forty-six minutes, forty seconds 10000.asString(style: .brief) // 2hr 46min 40sec 

6 Comments

@MaksimKniazev Usually time-oriented values are represented by Doubles in Swift.
@Adrian thank you for the extension. I like the .positional UnitStyle, however I would like to display ie: 9 seconds as "00:09" instead of "9", 1min 25 seconds as "01:25" instead of "1:25". I am able to achieve this calculating manually, based on Double value and I was wondering is there a way to incorporate into the extension itself? Thank you.
FYI: if you want to keep the 0s before a single digit value (or simply if the value is 0) you need to add this formatter.zeroFormattingBehavior = .pad. This would give us: 3660.asString(style: .positional) // 01:01:00
Note that DateComponentsFormatter isn't available on Linux
nanosecond break in swift5
|
42

In Swift 5:

 var i = 9897 func timeString(time: TimeInterval) -> String { let hour = Int(time) / 3600 let minute = Int(time) / 60 % 60 let second = Int(time) % 60 // return formated string return String(format: "%02i:%02i:%02i", hour, minute, second) } 

To call function

 timeString(time: TimeInterval(i)) 

Will return 02:44:57

3 Comments

Superb! Just what I required. I changed the 9897 for an Int variable and got the desired results. Thank you!
This doesn't work for me in Swift 5.3. I send it a TimeInterval value of 217368 milliseconds and it returns 60:22:48. 217368 milliseconds is 10:02.
@SouthernYankee65 Please pass seconds, not the milliseconds. It worked for me in Swift 5.3
31

I have built a mashup of existing answers to simplify everything and reduce the amount of code needed for Swift 3.

func hmsFrom(seconds: Int, completion: @escaping (_ hours: Int, _ minutes: Int, _ seconds: Int)->()) { completion(seconds / 3600, (seconds % 3600) / 60, (seconds % 3600) % 60) } func getStringFrom(seconds: Int) -> String { return seconds < 10 ? "0\(seconds)" : "\(seconds)" } 

Usage:

var seconds: Int = 100 hmsFrom(seconds: seconds) { hours, minutes, seconds in let hours = getStringFrom(seconds: hours) let minutes = getStringFrom(seconds: minutes) let seconds = getStringFrom(seconds: seconds) print("\(hours):\(minutes):\(seconds)") } 

Prints:

00:01:40

2 Comments

From my perspective, adding closure isn't really simplifies anything. Is there any good reason for closure?
@derpoliuk I've needed the closure for my specific needs in my app
28

Here is a more structured/flexible approach: (Swift 3)

struct StopWatch { var totalSeconds: Int var years: Int { return totalSeconds / 31536000 } var days: Int { return (totalSeconds % 31536000) / 86400 } var hours: Int { return (totalSeconds % 86400) / 3600 } var minutes: Int { return (totalSeconds % 3600) / 60 } var seconds: Int { return totalSeconds % 60 } //simplified to what OP wanted var hoursMinutesAndSeconds: (hours: Int, minutes: Int, seconds: Int) { return (hours, minutes, seconds) } } let watch = StopWatch(totalSeconds: 27005 + 31536000 + 86400) print(watch.years) // Prints 1 print(watch.days) // Prints 1 print(watch.hours) // Prints 7 print(watch.minutes) // Prints 30 print(watch.seconds) // Prints 5 print(watch.hoursMinutesAndSeconds) // Prints (7, 30, 5) 

Having an approach like this allows the adding of convenience parsing like this:

extension StopWatch { var simpleTimeString: String { let hoursText = timeText(from: hours) let minutesText = timeText(from: minutes) let secondsText = timeText(from: seconds) return "\(hoursText):\(minutesText):\(secondsText)" } private func timeText(from number: Int) -> String { return number < 10 ? "0\(number)" : "\(number)" } } print(watch.simpleTimeString) // Prints 07:30:05 

It should be noted that purely Integer based approaches don't take leap day/seconds into account. If the use case is dealing with real dates/times Date and Calendar should be used.

3 Comments

Could you please add month to your implementation? Thanks in advance!
You should use NSCalendar (Calendar) for something like that.
You could replace return number < 10 ? "0\(number)" : "\(number)" by using a string formatter return String(format: "%02d", number) which automatically adds a zero when the number is below 10
21

Xcode 12.1. Swift 5

DateComponentsFormatter: A formatter that creates string representations, by using unitsStyle u can get a string as you want and mention allowedUnits.

e.g: output for unitsStyle:: for 10000 secods

  1. full = "2 hours, 46 minutes, 49 seconds"
  2. positional = "2:46:40"
  3. abbreviated = "2h 46m 40s"
  4. spellOut = "two hours, forty-six minutes, forty seconds”
  5. short = "2hr,46 min,40 sec"
  6. brief = "2hr 46min 40sec"

Easy to use:

 let time = convertSecondsToHrMinuteSec(seconds: 10000) func convertSecondsToHrMinuteSec(seconds:Int) -> String{ let formatter = DateComponentsFormatter() formatter.allowedUnits = [.hour, .minute, .second] formatter.unitsStyle = .full let formattedString = formatter.string(from:TimeInterval(seconds))! print(formattedString) return formattedString } 

Comments

20

Swift 5:

extension Int { func secondsToTime() -> String { let (h,m,s) = (self / 3600, (self % 3600) / 60, (self % 3600) % 60) let h_string = h < 10 ? "0\(h)" : "\(h)" let m_string = m < 10 ? "0\(m)" : "\(m)" let s_string = s < 10 ? "0\(s)" : "\(s)" return "\(h_string):\(m_string):\(s_string)" } } 

Usage:

let seconds : Int = 119 print(seconds.secondsToTime()) // Result = "00:01:59" 

Comments

14

Swift 4

func formatSecondsToString(_ seconds: TimeInterval) -> String { if seconds.isNaN { return "00:00" } let Min = Int(seconds / 60) let Sec = Int(seconds.truncatingRemainder(dividingBy: 60)) return String(format: "%02d:%02d", Min, Sec) } 

2 Comments

What is truncatingRemainder ? Xcode does not recognize it for me.
you can read more about truncatingRemainder here
13

Here is another simple implementation in Swift3.

func seconds2Timestamp(intSeconds:Int)->String { let mins:Int = intSeconds/60 let hours:Int = mins/60 let secs:Int = intSeconds%60 let strTimestamp:String = ((hours<10) ? "0" : "") + String(hours) + ":" + ((mins<10) ? "0" : "") + String(mins) + ":" + ((secs<10) ? "0" : "") + String(secs) return strTimestamp } 

Comments

12

SWIFT 3.0 solution based roughly on the one above using extensions.

extension CMTime { var durationText:String { let totalSeconds = CMTimeGetSeconds(self) let hours:Int = Int(totalSeconds.truncatingRemainder(dividingBy: 86400) / 3600) let minutes:Int = Int(totalSeconds.truncatingRemainder(dividingBy: 3600) / 60) let seconds:Int = Int(totalSeconds.truncatingRemainder(dividingBy: 60)) if hours > 0 { return String(format: "%i:%02i:%02i", hours, minutes, seconds) } else { return String(format: "%02i:%02i", minutes, seconds) } } } 

Use it with AVPlayer calling it like this?

 let dTotalSeconds = self.player.currentTime() playingCurrentTime = dTotalSeconds.durationText 

Comments

8

I had answered to the similar question, however you don't need to display milliseconds in the result. Hence my solution requires iOS 10.0, tvOS 10.0, watchOS 3.0 or macOS 10.12.

You should call func convertDurationUnitValueToOtherUnits(durationValue:durationUnit:smallestUnitDuration:) from the answer that I already mentioned here:

let secondsToConvert = 27005 let result: [Int] = convertDurationUnitValueToOtherUnits( durationValue: Double(secondsToConvert), durationUnit: .seconds, smallestUnitDuration: .seconds ) print("\(result[0]) hours, \(result[1]) minutes, \(result[2]) seconds") // 7 hours, 30 minutes, 5 seconds 

Comments

7

Answer of @r3dm4n was great. However, I also needed hour in it. Just in case someone else needed too here it is:

func formatSecondsToString(_ seconds: TimeInterval) -> String { if seconds.isNaN { return "00:00:00" } let sec = Int(seconds.truncatingRemainder(dividingBy: 60)) let min = Int(seconds.truncatingRemainder(dividingBy: 3600) / 60) let hour = Int(seconds / 3600) return String(format: "%02d:%02d:%02d", hour, min, sec) } 

Comments

5

Swift 5 & String Response, In presentable format

public static func secondsToHoursMinutesSecondsStr (seconds : Int) -> String { let (hours, minutes, seconds) = secondsToHoursMinutesSeconds(seconds: seconds); var str = hours > 0 ? "\(hours) h" : "" str = minutes > 0 ? str + " \(minutes) min" : str str = seconds > 0 ? str + " \(seconds) sec" : str return str } public static func secondsToHoursMinutesSeconds (seconds : Int) -> (Int, Int, Int) { return (seconds / 3600, (seconds % 3600) / 60, (seconds % 3600) % 60) } 

Usage:

print(secondsToHoursMinutesSecondsStr(seconds: 20000)) // Result = "5 h 33 min 20 sec" 

Comments

3

According to GoZoner answer I have wrote an Extension to get the time formatted according to the hours, minute, and seconds:

extension Double { func secondsToHoursMinutesSeconds () -> (Int?, Int?, Int?) { let hrs = self / 3600 let mins = (self.truncatingRemainder(dividingBy: 3600)) / 60 let seconds = (self.truncatingRemainder(dividingBy:3600)).truncatingRemainder(dividingBy:60) return (Int(hrs) > 0 ? Int(hrs) : nil , Int(mins) > 0 ? Int(mins) : nil, Int(seconds) > 0 ? Int(seconds) : nil) } func printSecondsToHoursMinutesSeconds () -> String { let time = self.secondsToHoursMinutesSeconds() switch time { case (nil, let x? , let y?): return "\(x) min \(y) sec" case (nil, let x?, nil): return "\(x) min" case (let x?, nil, nil): return "\(x) hr" case (nil, nil, let x?): return "\(x) sec" case (let x?, nil, let z?): return "\(x) hr \(z) sec" case (let x?, let y?, nil): return "\(x) hr \(y) min" case (let x?, let y?, let z?): return "\(x) hr \(y) min \(z) sec" default: return "n/a" } } } let tmp = 3213123.printSecondsToHoursMinutesSeconds() // "892 hr 32 min 3 sec" 

Comments

3

Here is what I use for my Music Player in Swift 4+. I am converting seconds Int to readable String format

extension Int { var toAudioString: String { let h = self / 3600 let m = (self % 3600) / 60 let s = (self % 3600) % 60 return h > 0 ? String(format: "%1d:%02d:%02d", h, m, s) : String(format: "%1d:%02d", m, s) } } 

Use like this:

print(7903.toAudioString) 

Output: 2:11:43

Comments

3

Latest Code: XCode 10.4 Swift 5

extension Int { func timeDisplay() -> String { return "\(self / 3600):\((self % 3600) / 60):\((self % 3600) % 60)" } } 

Comments

3

From @Gamec answer

typealias CallDuration = Int extension CallDuration { func formatedString() -> String? { let hours = self / 3600 let minutes = (self / 60) % 60 let seconds = self % 60 if hours > 0 { return String(format: "%0.2d:%0.2d:%0.2d", hours, minutes, seconds) } return String(format: "%0.2d:%0.2d", minutes, seconds) } } 

Usage:

let duration: CallDuration = 3000 duration.formatedString() // 50 minute 

Comments

2

The simplest way imho:

let hours = time / 3600 let minutes = (time / 60) % 60 let seconds = time % 60 return String(format: "%0.2d:%0.2d:%0.2d", hours, minutes, seconds) 

2 Comments

It may be ld for double instead of d for int.
@NikeKov %ld is for long int. Use %f for double and float.
1

NSTimeInterval is Double do do it with extension. Example:

extension Double { var formattedTime: String { var formattedTime = "0:00" if self > 0 { let hours = Int(self / 3600) let minutes = Int(truncatingRemainder(dividingBy: 3600) / 60) formattedTime = String(hours) + ":" + (minutes < 10 ? "0" + String(minutes) : String(minutes)) } return formattedTime } } 

Comments

1

convert a number into time as a string

func convertToHMS(number: Int) -> String { let hour = number / 3600; let minute = (number % 3600) / 60; let second = (number % 3600) % 60 ; var h = String(hour); var m = String(minute); var s = String(second); if h.count == 1{ h = "0\(hour)"; } if m.count == 1{ m = "0\(minute)"; } if s.count == 1{ s = "0\(second)"; } return "\(h):\(m):\(s)" } print(convertToHMS(number:3900)) 

Comments

0

I went ahead and created a closure for this (in Swift 3).

let (m, s) = { (secs: Int) -> (Int, Int) in return ((secs % 3600) / 60, (secs % 3600) % 60) }(299) 

This will give m = 4 and s = 59. So you can format that as you wish. You may of course want to add hours as well, if not more information.

Comments

0

Swift 4 I'm using this extension

 extension Double { func stringFromInterval() -> String { let timeInterval = Int(self) let millisecondsInt = Int((self.truncatingRemainder(dividingBy: 1)) * 1000) let secondsInt = timeInterval % 60 let minutesInt = (timeInterval / 60) % 60 let hoursInt = (timeInterval / 3600) % 24 let daysInt = timeInterval / 86400 let milliseconds = "\(millisecondsInt)ms" let seconds = "\(secondsInt)s" + " " + milliseconds let minutes = "\(minutesInt)m" + " " + seconds let hours = "\(hoursInt)h" + " " + minutes let days = "\(daysInt)d" + " " + hours if daysInt > 0 { return days } if hoursInt > 0 { return hours } if minutesInt > 0 { return minutes } if secondsInt > 0 { return seconds } if millisecondsInt > 0 { return milliseconds } return "" } } 

useage

// assume myTimeInterval = 96460.397 myTimeInteval.stringFromInterval() // 1d 2h 47m 40s 397ms 

Comments

0

neek's answer isn't correct.

here's the correct version

func seconds2Timestamp(intSeconds:Int)->String { let mins:Int = (intSeconds/60)%60 let hours:Int = intSeconds/3600 let secs:Int = intSeconds%60 let strTimestamp:String = ((hours<10) ? "0" : "") + String(hours) + ":" + ((mins<10) ? "0" : "") + String(mins) + ":" + ((secs<10) ? "0" : "") + String(secs) return strTimestamp } 

Comments

0

Another way would be convert seconds to date and take the components i.e seconds, minutes and hour from date itself. This solution has limitation only till 23:59:59

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.