Swift - Konversi integer ke Jam / Menit / Detik


132

Saya punya (agak?) Pertanyaan mendasar mengenai konversi waktu di Swift .

Saya memiliki bilangan bulat yang ingin dikonversi menjadi Jam / Menit / Detik.

Contoh: Int = 27005 akan memberi saya:

7 Hours  30 Minutes 5 Seconds

Saya tahu bagaimana melakukan ini dalam PHP, tapi sayangnya, cepat bukan PHP :-)

Setiap tips tentang bagaimana saya dapat mencapainya dengan cepat akan sangat luar biasa! Terima kasih sebelumnya!

Jawaban:


296

Menetapkan

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

Menggunakan

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

atau

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

Fungsi di atas menggunakan tuple Swift untuk mengembalikan tiga nilai sekaligus. Anda merusak tuple menggunakanlet (var, ...) sintaks atau dapat mengakses setiap anggota tupel, jika perlu.

Jika Anda benar-benar perlu mencetaknya dengan kata-kata Hoursdll, maka gunakan sesuatu seperti ini:

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

Perhatikan bahwa implementasi secondsToHoursMinutesSeconds()karya di atas untuk Intargumen. Jika Anda menginginkan Doubleversi, Anda harus memutuskan apa nilai pengembaliannya - bisa (Int, Int, Double)atau bisa jadi (Double, Double, Double). Anda dapat mencoba sesuatu seperti:

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
Nilai terakhir (seconds % 3600) % 60dapat dioptimalkan untuk seconds % 60. Tidak perlu mengekstrak jam pertama.
zisoft

@GoZoner - sepertinya saya tidak bisa mendapatkan fungsi printSecondsToHoursMinutesSeconds agar berfungsi dengan benar. Inilah yang saya miliki di taman bermain, tetapi printSecondsToHoursMinutesSeconds tidak mengembalikan apa pun: impor UIKit func detikToHoursMinutesSeconds (detik: Int) -> (Int, Int, Int) {return (detik / 3600, (detik% 3600) / 60, (detik) % 3600)% 60)} let (h, m, s) = detikToHoursMinutesSeconds (27005) func printSecondsToHoursMinutesSeconds (detik: Int) -> () {let (h, m, s) = detikToHoursMinutesSeconds (detik) println (") ) Jam, (m) Menit, (s) Detik ")}
Joe

printSecondstoHoursMinutesSeconds()tidak mengembalikan apa pun (lihat -> ()tipe pengembalian dalam deklarasi fungsi). Fungsi mencetak sesuatu; yang tidak muncul di Playground. Jika Anda ingin mengembalikan sesuatu, ucapkan a Stringlalu hilangkan println()panggilan dan perbaiki jenis pengembalian fungsi.
GoZoner

@GoZoner - hanya pertanyaan singkat di sintaks Anda di atas. Bagaimana saya menyatakan bahwa 27005 dalam suatu variabel? Saya sedang mengerjakan alat sekarang untuk membuat kaki saya basah dengan cepat. Saya memiliki konstanta yang menampilkan jumlah detik (dihasilkan setelah perhitungan dasar saya). biarkan cocSeconds = cocMinutes * 60. (cocSeconds adalah apa yang ingin saya gunakan di tempat 27005.) Saya pikir masalah yang saya miliki adalah cocSeconds adalah ganda, dan dalam sintaks Anda, Anda menggunakan Ints. Bagaimana cara saya menyesuaikan kode ini untuk meletakkan variabel di tempat 27005? Terima kasih banyak sebelumnya!!!
Joe

Solusi yang saya berikan berfungsi untuk Intjenis karena sifat /dan %fungsinya. Itu adalah /bagian faksi. Kode yang sama tidak akan berfungsi untuk Double. Khususnya 2 == 13/5 tetapi 2.6 == 13.0 / 5. Karenanya Anda akan memerlukan implementasi yang berbeda untuk Double. Saya telah memperbarui jawaban saya dengan catatan tentang ini.
GoZoner

172

Di macOS 10.10+ / iOS 8.0+ (NS)DateComponentsFormattertelah diperkenalkan untuk membuat string yang dapat dibaca.

Ini mempertimbangkan lokal dan bahasa pengguna.

let interval = 27005

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

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

Gaya unit yang tersedia adalah positional, abbreviated, short, full, spellOutdan brief.

Untuk informasi lebih lanjut silakan baca dokumentasi .


19
Menggunakan formatter.unitsStyle = .positionalmemberi apa yang saya inginkan (yaitu 7:30:05)! Jawaban terbaik IMO
Sam

11
Dan Anda dapat menambahkan nol `` `formatter.zeroFormattingBehavior = .pad` ``
Eduardo Irias

Cara mendapatkan sebaliknya ini. Itulah cara mengonversi Jam, Menit ke detik
Angel F Syrus

1
@AngelFSyrus Simplyhours * 3600 + minutes * 60
vadian

59

Membangun berdasarkan jawaban Vadian , saya menulis ekstensi yang mengambil Double(yang TimeIntervalmerupakan jenis alias) dan meludahkan string yang diformat sebagai waktu.

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

Berikut adalah beberapa DateComponentsFormatter.UnitsStylepilihan:

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 Biasanya nilai berorientasi waktu diwakili oleh Doublesdi Swift.
Adrian

@Adrian terima kasih atas ekstensi. Saya suka .positional UnitStyle, namun saya ingin menampilkan yaitu: 9 detik sebagai "00:09" bukannya "9", 1 menit 25 detik sebagai "01:25" bukannya "1:25". Saya dapat mencapai penghitungan ini secara manual, berdasarkan nilai Double dan saya bertanya-tanya apakah ada cara untuk memasukkannya ke dalam ekstensi itu sendiri? Terima kasih.
Vetuka

FYI: jika Anda ingin menyimpan 0 sebelum nilai satu digit (atau hanya jika nilainya 0), Anda perlu menambahkan ini formatter.zeroFormattingBehavior = .pad. Ini akan memberi kita:3660.asString(style: .positional) // 01:01:00
Moucheg

27

Saya telah membangun kumpulan jawaban yang ada untuk menyederhanakan semuanya dan mengurangi jumlah kode yang diperlukan untuk 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)"
}

Pemakaian:

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

Cetakan:

00:01:40


5
Dari sudut pandang saya, menambahkan penutupan tidak benar-benar menyederhanakan apa pun. Apakah ada alasan bagus untuk penutupan?
derpoliuk

@derpoliuk Saya membutuhkan penutupan untuk kebutuhan spesifik saya di aplikasi saya
David Seek

24

Berikut ini adalah pendekatan yang lebih terstruktur / fleksibel: (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)

Memiliki pendekatan seperti ini memungkinkan penambahan parsing kenyamanan seperti ini:

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

Perlu dicatat bahwa pendekatan murni bilangan bulat tidak memperhitungkan hari / detik. Jika use case berurusan dengan tanggal / waktu nyata Tanggal dan Kalender harus digunakan.


Bisakah Anda menambahkan monthke implementasi Anda? Terima kasih sebelumnya!
ixany

3
Anda harus menggunakan NSCalendar (Kalender) untuk hal seperti itu.
NoLongerContributingToSE

Anda bisa mengganti return number < 10 ? "0\(number)" : "\(number)"dengan menggunakan formatter string return String(format: "%02d", number)yang secara otomatis menambahkan nol ketika jumlahnya di bawah 10
Continuum

19

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

Untuk memanggil fungsi

    timeString(time: TimeInterval(i))

Akan kembali 02:44:57


Hebat! Apa yang saya butuhkan. Saya mengubah 9897 untuk variabel Int dan mendapatkan hasil yang diinginkan. Terima kasih!
David_2877

13

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

Apa itu truncatingRemainder? Xcode tidak mengenalinya untuk saya.
Alfi

10

Berikut ini adalah implementasi sederhana lainnya di 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

Solusi SWIFT 3.0 didasarkan pada yang di atas menggunakan ekstensi.

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

  }
}

Gunakan dengan AVPlayer menyebutnya seperti ini?

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

8

Saya telah menjawab pertanyaan serupa , namun Anda tidak perlu menampilkan milidetik dalam hasilnya. Karenanya solusi saya membutuhkan iOS 10.0, tvOS 10.0, watchOS 3.0 atau macOS 10.12.

Anda harus menelepon func convertDurationUnitValueToOtherUnits(durationValue:durationUnit:smallestUnitDuration:)dari jawaban yang sudah saya sebutkan di sini:

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

Pemakaian:

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

3

Menurut jawaban GoZoner saya telah menulis Ekstensi untuk mendapatkan waktu yang diformat sesuai dengan jam, menit, dan detik:

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

Inilah yang saya gunakan untuk Pemutar Musik saya di Swift 4+. Saya mengkonversi detik Int ke format String yang dapat dibaca

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

Gunakan seperti ini:

print(7903.toAudioString)

Keluaran: 2:11:43


3

Jawaban dari @ r3dm4n sangat bagus. Namun, saya juga perlu satu jam di dalamnya. Untuk berjaga-jaga jika ada orang lain yang membutuhkannya di sini:

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

Kode Terbaru: XCode 10.4 Swift 5

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

2

Swift 5 & String Response, Dalam format yang rapi

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

Pemakaian:

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

1

Cara termudah:

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)

Mungkin lduntuk double, bukan duntuk int.
Nik Kov

1

NSTimeIntervaladalah Doublelakukan dengan ekstensi. Contoh:

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

Saya pergi ke depan dan membuat penutupan untuk ini (dalam Swift 3).

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

Ini akan memberikan m = 4 dan s = 59. Jadi Anda dapat memformat sesuai keinginan. Anda tentu saja ingin menambahkan jam juga, jika tidak ada informasi lebih lanjut.


0

Swift 4 Saya menggunakan ekstensi ini

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

penggunaan

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

0

jawaban neek tidak benar.

ini versi yang benar

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

Cara lain akan mengkonversi detik ke tanggal dan mengambil komponen yaitu detik, menit dan jam dari tanggal itu sendiri. Solusi ini memiliki batasan hanya hingga 23:59:59

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.