J'ai une question de base (un peu?) Concernant les conversions de temps dans Swift .
J'ai un entier que je voudrais convertir en heures/minutes/secondes.
Exemple: Int = 27005
me donnerait:
7 Hours 30 Minutes 5 Seconds
Je sais comment faire cela en PHP, mais hélas, Swift n'est pas PHP :-)
Tous les conseils sur la façon dont je peux atteindre cet objectif dans Swift seraient fantastiques! Merci d'avance!
Définir
func secondsToHoursMinutesSeconds (seconds : Int) -> (Int, Int, Int) {
return (seconds / 3600, (seconds % 3600) / 60, (seconds % 3600) % 60)
}
Utilisation
> secondsToHoursMinutesSeconds(27005)
(7,30,5)
ou
let (h,m,s) = secondsToHoursMinutesSeconds(27005)
La fonction ci-dessus utilise les tuples rapides pour renvoyer trois valeurs à la fois. Vous pouvez déstructurer le tuple à l'aide de la syntaxe let (var, ...)
ou accéder aux membres individuels du tuple, le cas échéant.
Si vous avez réellement besoin de l’imprimer avec les mots Hours
etc etc, utilisez quelque chose comme ceci:
func printSecondsToHoursMinutesSeconds (seconds:Int) -> () {
let (h, m, s) = secondsToHoursMinutesSeconds (seconds)
print ("\(h) Hours, \(m) Minutes, \(s) Seconds")
}
Notez que l'implémentation ci-dessus de secondsToHoursMinutesSeconds()
fonctionne pour les arguments Int
. Si vous voulez une version Double
, vous devez déterminer quelles sont les valeurs de retour. Il peut s'agir de (Int, Int, Double)
ou de (Double, Double, Double)
. Vous pouvez essayer quelque chose comme:
func secondsToHoursMinutesSeconds (seconds : Double) -> (Double, Double, Double) {
let (hr, minf) = modf (seconds / 3600)
let (min, secf) = modf (60 * minf)
return (hr, min, 60 * secf)
}
Dans macOS 10.10+/iOS 8.0+, (NS)DateComponentsFormatter
a été introduit pour créer une chaîne lisible.
Il considère les paramètres régionaux et la langue de l'utilisateur.
let interval = 27005
let formatter = DateComponentsFormatter()
formatter.allowedUnits = [.hour, .minute, .second]
formatter.unitsStyle = .full
let formattedString = formatter.string(from: TimeInterval(interval))!
print(formattedString)
Les styles d'unité disponibles sont positional
, abbreviated
, short
, full
, spellOut
et brief
.
Pour plus d'informations, veuillez lire la documenation .
J'ai construit un mashup de réponses existantes pour tout simplifier et réduire la quantité de code nécessaire pour 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)")
}
Impressions:
00:01:40
S'appuyant sur La réponse de Vadian , j'ai écrit une extension qui prend une Double
(dont TimeInterval
est un alias de type) et crache une chaîne au format time.
extension Double {
func asString(style: DateComponentsFormatter.UnitsStyle) -> String {
let formatter = DateComponentsFormatter()
formatter.allowedUnits = [.hour, .minute, .second, .nanosecond]
formatter.unitsStyle = style
guard let formattedString = formatter.string(from: self) else { return "" }
return formattedString
}
}
Voici à quoi ressemblent les différentes options DateComponentsFormatter.UnitsStyle
:
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
Voici une approche plus structurée/flexible: (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)
Avoir une approche comme celle-ci permet d'ajouter une analyse de commodité comme celle-ci:
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
Il convient de noter que les approches purement entières ne prennent pas en compte les jours bissextiles. Si le cas d'utilisation concerne des dates/heures réelles Date et Calendrier doit être utilisé.
Voici une autre implémentation simple dans 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
}
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)
}
Solution Swift 3.0 basée à peu près sur celle ci-dessus utilisant des 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)
}
}
}
Utilisez-le avec AVPlayer en l'appelant ainsi?
let dTotalSeconds = self.player.currentTime()
playingCurrentTime = dTotalSeconds.durationText
Dans 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)
}
Appeler la fonction
timeString(time: TimeInterval(i))
Je reviendrai 2:44:57
Si la cible de votre application est iOS 10.0 ou plus récent, vous pouvez utiliser Measurement
pour convertir le nombre de secondes en heures, minutes et secondes. Dans Swift 4.2.1/Xcode 10.1, vous pouvez utiliser cette fonction pour convertir la valeur de la durée d'une unité en secondes:
func convert<MeasurementType: BinaryInteger>(measurementValue: MeasurementType,
unitDuration: UnitDuration) -> (MeasurementType, MeasurementType) {
let measurementSeconds = Measurement<UnitDuration>(value: Double(measurementValue),
unit: .seconds)
let secondsCount = MeasurementType(measurementSeconds.converted(to: unitDuration).value)
let measurementCurrentUnit = Measurement(value: Double(secondsCount),
unit: unitDuration)
let currentUnitCount = MeasurementType(measurementCurrentUnit.converted(to: .seconds).value)
return (secondsCount, measurementValue - currentUnitCount)
}
Pour obtenir une valeur requise, appelez-la deux fois:
func convertSecondsToHoursMinutesSeconds<MeasurementType: BinaryInteger>(seconds: MeasurementType) -> (MeasurementType, MeasurementType, MeasurementType) {
let hoursAndRestSeconds = convert(measurementValue: seconds, unitDuration: .hours)
let minutesAndRestSeconds = convert(measurementValue: hoursAndRestSeconds.1, unitDuration: .minutes)
return (hoursAndRestSeconds.0, minutesAndRestSeconds.0, minutesAndRestSeconds.1)
}
Comment l'utiliser:
let result = convertSecondsToHoursMinutesSeconds(seconds: 27005)
print("\(result.0) Hours \(result.1) Minutes \(result.2) Seconds")
Comme vous pouvez le constater, je n’ai pas utilisé 60, 3600 ou d’autres constantes numériques dans ma solution.
Selon GoZoner answer, j'ai écrit une extension pour que le heure soit formaté en fonction des heures, des minutes et des secondes:
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"
Réponse de @ r3dm4n était super. Cependant, j'avais aussi besoin d'une heure. Juste au cas où quelqu'un aurait besoin de vous aussi, voici:
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)
}
NSTimeInterval
est Double
faire avec extension. Exemple:
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
}
}
Le moyen le plus simple à mon humble avis:
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)
Voici ce que j'utilise pour mon lecteur de musique dans Swift 4+. Je convertis des secondes Int en format lisible String
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)
}
}
Utilisez comme ceci:
print(7903.toAudioString)
Sortie: 2:11:43
Swift 4 J'utilise cette 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 ""
}
}
utilisation
// assume myTimeInterval = 96460.397
myTimeInteval.stringFromInterval() // 1d 2h 47m 40s 397ms
Je suis allé de l'avant et créé une fermeture pour cela (dans Swift 3).
let (m, s) = { (secs: Int) -> (Int, Int) in
return ((secs % 3600) / 60, (secs % 3600) % 60) }(299)
Cela donnera m = 4 et s = 59. Vous pouvez donc formater cela à votre guise. Vous pouvez bien sûr vouloir ajouter des heures aussi, sinon plus d'informations.
La réponse de neek n'est pas correcte.
voici la bonne 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
}