Rapido: conversione di numeri interi in ore / minuti / secondi


132

Ho una domanda (un po '?) Di base per quanto riguarda le conversioni di tempo in Swift .

Ho un numero intero che vorrei convertire in ore / minuti / secondi.

Esempio: Int = 27005 mi darebbe:

7 Hours  30 Minutes 5 Seconds

So come farlo in PHP, ma ahimè, rapido non è PHP :-)

Eventuali suggerimenti su come posso ottenere questo in breve tempo sarebbero fantastici! Grazie in anticipo!

Risposte:


296

Definire

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

Uso

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

o

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

La funzione sopra fa uso delle tuple Swift per restituire tre valori contemporaneamente. Distruggi la tupla usando la let (var, ...)sintassi o puoi accedere ai singoli membri della tupla, se necessario.

Se hai davvero bisogno di stamparlo con le parole Hoursecc., Usa qualcosa del genere:

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

Si noti che l'implementazione di cui sopra secondsToHoursMinutesSeconds()funziona per Intargomenti. Se vuoi una Doubleversione dovrai decidere quali sono i valori di ritorno - potrebbero essere (Int, Int, Double)o potrebbero essere (Double, Double, Double). Potresti provare qualcosa del tipo:

func secondsToHoursMinutesSeconds (seconds : Double) -> (Double, Double, Double) {
  let (hr,  minf) = modf (seconds / 3600)
  let (min, secf) = modf (60 * minf)
  return (hr, min, 60 * secf)
}

14
L'ultimo valore (seconds % 3600) % 60può essere ottimizzato su seconds % 60. Non è necessario estrarre prima le ore.
zisoft,

@GoZoner - sembra che la funzione printSecondsToHoursMinutesSeconds non funzioni correttamente. Questo è quello che ho in un parco giochi, ma printSecondsToHoursMinutesSeconds non restituisce nulla: importa UIKit func secondsToHoursMinutesSeconds (secondi: Int) -> (Int, Int, Int) {return (secondi / 3600, (secondi% 3600) / 60, (secondi % 3600)% 60)} let (h, m, s) = secondsToHoursMinutesSeconds (27005) func printSecondsToHoursMinutesSeconds (secondi: Int) -> () {let (h, m, s) = secondsToHoursMinutesSeconds (seconds) println ("(h ) Ore, (m) minuti, (s) secondi ")}
Joe,

printSecondstoHoursMinutesSeconds()non restituisce nulla (vedere il -> ()tipo restituito nella dichiarazione della funzione). La funzione stampa qualcosa; che non compare in un parco giochi. Se si desidera che restituisca qualcosa, dire a, Stringquindi eliminare la println()chiamata e correggere il tipo di ritorno della funzione.
GoZoner,

@GoZoner - solo una domanda veloce nella tua sintassi sopra. Come dichiarerei quel 27005 in una variabile? Sto lavorando a uno strumento in questo momento per bagnarmi i piedi con rapidità. Ho una costante che visualizza la quantità di secondi (generata dopo i miei calcoli di base). let cocSeconds = cocMinutes * 60. (cocSeconds è quello che voglio usare al posto di 27005.) Penso che il problema che sto avendo è cocSeconds è un doppio, e nella tua sintassi stai usando Ints. Come potrei fare per regolare questo codice per inserire una variabile al posto di 27005? Grazie mille in anticipo !!!
Joe,

La soluzione che ho dato funziona per Inttipi a causa della natura delle funzioni /e %. Cioè /lascia cadere la parte della fazione. Lo stesso codice non funzionerà per Double. In particolare 2 == 13/5 ma 2.6 == 13.0 / 5. Pertanto avresti bisogno di un'implementazione diversa per Double. Ho aggiornato la mia risposta con una nota al riguardo.
GoZoner,

172

In macOS 10.10+ / iOS 8.0+ (NS)DateComponentsFormatterè stato introdotto per creare una stringa leggibile.

Considera le impostazioni locali e la lingua dell'utente.

let interval = 27005

let formatter = DateComponentsFormatter()
formatter.allowedUnits = [.hour, .minute, .second]
formatter.unitsStyle = .full

let formattedString = formatter.string(from: TimeInterval(interval))!
print(formattedString)

Gli stili di unità disponibili sono positional, abbreviated, short, full, spellOute brief.

Per maggiori informazioni leggi la documentazione .


19
L'utilizzo formatter.unitsStyle = .positionaldà esattamente quello che voglio (che è 7:30:05)! Migliore risposta IMO
Sam,

11
E puoi aggiungere lo zero `` `formatter.zeroFormattingBehavior = .pad` ``
Eduardo Irias,

Come ottenere il viceversa di questo. Ecco come convertire l'ora, il minuto in secondi
Angel F Syrus,

1
@AngelFSyrus Simplyhours * 3600 + minutes * 60
vadian

59

Sulla base risposta di Vadian , ho scritto un'estensione che prende una Double(di cui TimeIntervalè un tipo alias) e sputa fuori una stringa formattata come il tempo.

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
  }
}

Ecco come appaiono le varie DateComponentsFormatter.UnitsStyleopzioni:

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

@MaksimKniazev Di solito i valori orientati al tempo sono rappresentati da DoublesSwift.
Adrian,

@Adrian grazie per l'estensione. Mi piace il .posizionale UnitStyle, tuttavia vorrei visualizzare ad es .: 9 secondi come "00:09" invece di "9", 1min 25 secondi come "01:25" anziché "1:25". Sono in grado di ottenere questo calcolo manualmente, in base al doppio valore e mi chiedevo c'è un modo per incorporare l'estensione stessa? Grazie.
Vetuka,

Cordiali saluti: se si desidera mantenere gli 0 prima di un valore a singola cifra (o semplicemente se il valore è 0) è necessario aggiungere questo formatter.zeroFormattingBehavior = .pad. Questo ci darebbe:3660.asString(style: .positional) // 01:01:00
Moucheg

27

Ho creato un mashup di risposte esistenti per semplificare tutto e ridurre la quantità di codice necessario per 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)"
}

Uso:

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)")                
}

stampe:

00:01:40


5
Dal mio punto di vista, l'aggiunta di chiusura non semplifica davvero nulla. C'è qualche buona ragione per la chiusura?
derpoliuk,

@derpoliuk Ho avuto bisogno della chiusura per le mie esigenze specifiche nella mia app
David Seek

24

Ecco un approccio più strutturato / flessibile: (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)

Avere un approccio come questo consente l'aggiunta di analisi di convenienza come questa:

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

Va notato che gli approcci basati esclusivamente su numeri interi non tengono conto del giorno / dei secondi del salto. Se il caso d'uso ha a che fare con date / orari reali necessario utilizzare Data e Calendario .


Potresti aggiungere monthalla tua implementazione? Grazie in anticipo!
IX

3
Dovresti usare NSCalendar (Calendario) per qualcosa del genere.
NoLongerContributingToSE

È possibile sostituire return number < 10 ? "0\(number)" : "\(number)"utilizzando un formattatore di stringhe return String(format: "%02d", number)che aggiunge automaticamente uno zero quando il numero è inferiore a 10
Continuum

19

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)
    }

Per chiamare la funzione

    timeString(time: TimeInterval(i))

Tornerà 02:44:57


Stupendo! Proprio quello che ho richiesto. Ho cambiato il 9897 per una variabile Int e ho ottenuto i risultati desiderati. Grazie!
David_2877,

13

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)
}

Cos'è TruncatingRemainder? Xcode non lo riconosce per me.
Alfi,

10

Ecco un'altra semplice implementazione 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
}

9

Soluzione SWIFT 3.0 basata approssimativamente su quella precedente usando estensioni.

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)
    }

  }
}

Usalo con AVPlayer chiamandolo così?

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

8

Avevo risposto alla domanda simile , tuttavia non è necessario visualizzare i millisecondi nel risultato. Quindi la mia soluzione richiede iOS 10.0, tvOS 10.0, watchOS 3.0 o macOS 10.12.

Dovresti chiamare func convertDurationUnitValueToOtherUnits(durationValue:durationUnit:smallestUnitDuration:)dalla risposta che ho già menzionato qui:

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

5

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)"
    }
}

Uso:

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

3

Secondo la risposta di GoZoner, ho scritto un'estensione per ottenere il tempo formattato in base alle ore, ai minuti e ai secondi:

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"

3

Ecco cosa uso per il mio lettore musicale in Swift 4+. Io sono la conversione secondi Int a leggibile stringa formato

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)
    }
}

Usa così:

print(7903.toAudioString)

Produzione: 2:11:43


3

La risposta di @ r3dm4n è stata fantastica. Tuttavia, ho avuto bisogno anche di un'ora. Nel caso in cui fosse necessario qualcun altro, eccolo:

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)
}

3

Ultimo codice: XCode 10.4 Swift 5

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

2

Swift 5 & String Response, in formato presentabile

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)
 }

Uso:

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

1

Il modo più semplice 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)

Può essere ldper double anziché dper int.
Nik Kov,

1

NSTimeIntervalè Doublefarlo con l'estensione. Esempio:

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
    }
}

0

Sono andato avanti e ho creato una chiusura per questo (in Swift 3).

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

Questo darà m = 4 e s = 59. Quindi puoi formattarlo come desideri. Ovviamente potresti anche voler aggiungere ore, se non maggiori informazioni.


0

Swift 4 Sto usando questa estensione

 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

0

la risposta di Neek non è corretta.

ecco la versione corretta

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
}

0

Un altro modo sarebbe convertire i secondi fino ad oggi e prendere i componenti, cioè secondi, minuti e ora dalla data stessa. Questa soluzione ha limitazioni solo fino alle 23:59:59

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.