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!

Joe
sumber

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)
}
GoZoner
sumber
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 .

Vadian
sumber
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
Adrian
sumber
@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

David Seek
sumber
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.

NoLongerContributingToSE
sumber
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

DialDT
sumber
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)
}
r3dm4n
sumber
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
}
neeks
sumber
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
pengguna3069232
sumber
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
Roman Podymov
sumber
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"
ZAFAR007
sumber
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"
xGoPox
sumber
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

Maksim Kniazev
sumber
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)
}
Vetuka
sumber
3

Kode Terbaru: XCode 10.4 Swift 5

extension Int {
    func timeDisplay() -> String {
        return "\(self / 3600):\((self % 3600) / 60):\((self % 3600) % 60)"
    }
}
Saranjith
sumber
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"
Asad Ali Choudhry
sumber
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)
Gamec
sumber
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
    }
}
Bartłomiej Semańczyk
sumber
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.

Torbjørn Kristoffersen
sumber
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
caesss
sumber
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
}
Ali H Essayli
sumber
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

Wasim
sumber