Swift - Saat / Dakika / Saniyeye Tamsayı dönüştürme


133

Ben de zaman dönüşüm konusunda (biraz?) Temel soru var Swift .

Saat / Dakika / Saniyeye dönüştürmek istediğim bir tamsayı var.

Örnek: Int = 27005 bana şunu verir:

7 Hours  30 Minutes 5 Seconds

Bunu PHP'de nasıl yapacağımı biliyorum ama ne yazık ki, hızlı PHP değil :-)

Bunu hızlı bir şekilde nasıl başarabileceğime dair herhangi bir ipucu harika olurdu! Şimdiden teşekkür ederim!

Yanıtlar:


297

Tanımlamak

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

kullanım

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

veya

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

Yukarıdaki işlev, aynı anda üç değer döndürmek için Swift kayıtlarını kullanır. let (var, ...)Sözdizimini kullanarak tuple'ı yok edersiniz veya gerekirse bireysel demet üyelerine erişebilirsiniz.

Aslında kelimelerin Hoursvb . İle çıktısını almanız gerekiyorsa, bunun gibi bir şey kullanın:

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

Yukarıdaki uygulamaların argümanlar secondsToHoursMinutesSeconds()için çalıştığını unutmayın Int. Bir Doublesürüm istiyorsanız, dönüş değerlerinin ne olabileceğine (Int, Int, Double)veya olabileceğine karar vermeniz gerekir (Double, Double, Double). Şöyle bir şey deneyebilirsiniz:

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
Son değer (seconds % 3600) % 60optimize edilebilir seconds % 60. Önce saatleri çıkarmanıza gerek yok.
zisoft

@GoZoner - printSecondsToHoursMinutesSeconds işlevinin düzgün çalıştığını göremiyorum. Bir oyun alanında sahip olduğum şey bu, ancak printSecondsToHoursMinutesSeconds hiçbir şey döndürmüyor: 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 ) Saat, (m) Dakika, (s) Saniye ")}
Joe

printSecondstoHoursMinutesSeconds()hiçbir şey döndürmez ( -> ()işlev bildirimindeki dönüş türüne bakın ). İşlev bir şey yazdırır; Oyun Alanında görünmeyen. Bir şeyi döndürmesini istiyorsanız, a deyin, Stringardından println()çağrıyı kaldırın ve işlevin dönüş türünü düzeltin.
GoZoner

@GoZoner - yukarıdaki söz diziminizde kısa bir soru. 27005'i bir değişkende nasıl ilan ederim? Şu anda ayaklarımı hızlı bir şekilde ıslatmak için bir alet üzerinde çalışıyorum. Saniyelerin miktarını gösteren bir sabite sahibim (temel hesaplamalarımdan sonra oluşturulmuş). let cocSeconds = cocMinutes * 60. (benim 27005 yerine kullanmak istediğim cocSeconds.) Sanırım benim yaşadığım problem cocSeconds'un bir çift ve sözdiziminize göre İnts kullanıyorsunuz. 27005'in yerine bir değişken yerleştirmek için bu kodu nasıl ayarlayabilirim? Şimdiden çok teşekkür ederim!!!
Joe

Verdiğim çözüm Int, /ve %işlevlerinin doğası gereği türler için çalışıyor . Bu, /hizipsel kısmı düşürür. Aynı kod işe yaramaz Double. Özellikle 2 == 13/5 ancak 2.6 == 13.0 / 5. Bu nedenle için farklı bir uygulamaya ihtiyacınız olacaktır Double. Cevabımı bununla ilgili bir notla güncelledim.
GoZoner

173

MacOS 10.10+ / iOS 8.0+ sürümlerinde (NS)DateComponentsFormatterOkunabilir bir dize oluşturmak için kullanıma sunulmuştur.

Kullanıcının yerel ayarını ve dilini dikkate alır.

let interval = 27005

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

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

Mevcut birim stilleri positional, abbreviated, short, full, spellOutvebrief .

Daha fazla bilgi için lütfen dokümantasyonu okuyun .


19
Kullanmak formatter.unitsStyle = .positionaltam olarak istediğimi verir (ki bu 7:30:05)! En iyi cevap IMO
Sam

11
Ve sıfır `` formatter.zeroFormattingBehavior = .pad '' ekleyebilirsiniz
Eduardo Irias

Bunun tersi nasıl yapılır? Saat, Dakika'yı saniyeye dönüştürme yöntemi budur
Angel F Syrus

1
@AngelFSyrus Simplyhours * 3600 + minutes * 60
vadian

59

Üzerine bina Vadian cevabı , bir bir sürer uzantısı yazdı Double(hangi TimeIntervalzaman olarak biçimlendirilmiş bir dize dışında bir tip diğer adıdır) ve tükürür.

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

Çeşitli DateComponentsFormatter.UnitsStyleseçenekler şu şekildedir :

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 Genellikle zamana yönelik değerler DoublesSwift ile temsil edilir .
Adrian

@Adrian uzantı için teşekkür ederim. .Pozisyonel UnitStyle'ı seviyorum, ancak ie: 9 saniyeyi "9" yerine "00:09" olarak, 1 dakika 25 saniyeyi "1:25" yerine "01:25" olarak görüntülemek istiyorum. Bu hesaplamayı, Çift değere dayalı olarak manuel olarak yapabiliyorum ve merak ediyordum, uzantının kendisine dahil etmenin bir yolu var mı? Teşekkür ederim.
Vetuka

Bilginize: 0'ları tek basamaklı bir değerden önce tutmak istiyorsanız (veya sadece değer 0 ise) bunu eklemeniz gerekir formatter.zeroFormattingBehavior = .pad. Bu bize şunu verir:3660.asString(style: .positional) // 01:01:00
Moucheg

27

Her şeyi basitleştirmek ve Swift 3 için gereken kod miktarını azaltmak için mevcut yanıtların bir karışımını oluşturdum .

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

Kullanımı:

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

Baskılar:

00:01:40


5
Benim bakış açıma göre, kapanış eklemek gerçekten hiçbir şeyi basitleştirmiyor. Kapatmak için iyi bir sebep var mı?
derpoliuk

@derpoliuk Uygulamamdaki özel ihtiyaçlarım için kapanışa ihtiyacım var
David Seek

24

İşte daha yapılandırılmış / esnek bir yaklaşım: (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)

Böyle bir yaklaşıma sahip olmak, şu şekilde ayrıştırmaya olanak sağlar:

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

Tamamen Tamsayı tabanlı yaklaşımların artık gün / saniyeyi hesaba katmadığı unutulmamalıdır. Kullanım senaryosu gerçek tarihler / saatler ile ilgiliyse Tarih ve Takvim kullanılmalıdır.


Lütfen monthuygulamanıza bir şeyler ekler misiniz ? Şimdiden teşekkürler!
ixany

3
Bunun gibi bir şey için NSCalendar (Takvim) kullanmalısınız.
NoLongerContributingToSE

Sen yerini alabilecek return number < 10 ? "0\(number)" : "\(number)"bir dize biçimlendirici kullanarak return String(format: "%02d", number)10'dan az sayıda otomatik sıfır ekler
Continuum

19

Swift 5'te:

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

Fonksiyonu aramak için

    timeString(time: TimeInterval(i))

Döndürür 02:44:57


Süper! Tam da istediğim gibi. 9897'yi bir Int değişkeni için değiştirdim ve istenen sonuçları aldım. Teşekkür ederim!
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)
}

TruncatingRemainder nedir? Xcode benim için onu tanımıyor.
Alfi

10

İşte Swift3'teki başka bir basit uygulama.

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

SWIFT 3.0 çözümü, aşağı yukarı uzantı kullanan yukarıdaki çözümlere dayanmaktadır.

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

  }
}

AVPlayer'ı böyle çağırarak kullanmak ister misiniz?

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

8

Benzer soruya cevap vermiştim ancak sonuç ekran milisaniye gerekmez. Dolayısıyla benim çözümüm iOS 10.0, tvOS 10.0, watchOS 3.0 veya macOS 10.12 gerektiriyor.

func convertDurationUnitValueToOtherUnits(durationValue:durationUnit:smallestUnitDuration:)Burada daha önce bahsettiğim cevaptan aramalısın :

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

Kullanımı:

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

3

Göre GoZoner cevap ben almak için bir Uzantısı yazdı biçimlendirilmiş zaman saat, dakika ve saniye göre:

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

İşte Swift 4+ 'de Müzik Çalarım için kullandığım şey. Ben et saniye dönüştürme am Int okunabilir için dize biçimi

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

Bunun gibi kullanın:

print(7903.toAudioString)

Çıktı: 2:11:43


3

Cevap @ r3dm4n büyük oldu. Ancak, içinde bir saate de ihtiyacım vardı. Sadece başka birinin de ihtiyacı olması durumunda burada:

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

Son Kod: XCode 10.4 Swift 5

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

2

Swift 5 & String Response, Sunulabilir formatta

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

Kullanımı:

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

1

En basit yol 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)

İnt ldyerine double olabilir d.
Nik Kov

1

NSTimeIntervalolan Doubleuzantısı ile bunu do. Misal:

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

Devam ettim ve bunun için bir kapanış yarattım (Swift 3'te).

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

Bu, m = 4 ve s = 59 verecek. Yani bunu istediğiniz gibi biçimlendirebilirsiniz. Daha fazla bilgi değilse tabii ki saatleri de eklemek isteyebilirsiniz.


0

Swift 4 Bu uzantıyı kullanıyorum

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

useagenin

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

0

neek'in cevabı doğru değil.

işte doğru versiyon

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

Başka bir yol, saniyeleri tarihe dönüştürmek ve bileşenleri, yani tarihin kendisinden saniye, dakika ve saat almaktır. Bu çözümün yalnızca 23:59: 59'a kadar sınırlaması vardır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.