Swift - การแปลงจำนวนเต็มเป็นชั่วโมง / นาที / วินาที


131

ฉันมี (บ้าง?) คำถามพื้นฐานเกี่ยวกับการแปลงเวลาในสวิฟท์

ฉันมีจำนวนเต็มที่ฉันต้องการแปลงเป็นชั่วโมง / นาที / วินาที

ตัวอย่าง: Int = 27005จะให้ฉัน:

7 Hours  30 Minutes 5 Seconds

ฉันรู้วิธีการทำเช่นนี้ใน PHP แต่อนิจจาสวิฟท์ไม่ใช่ PHP :-)

เคล็ดลับใด ๆ เกี่ยวกับวิธีที่ฉันสามารถบรรลุสิ่งนี้ได้อย่างรวดเร็วจะเป็นเรื่องที่ยอดเยี่ยม! ขอบคุณล่วงหน้า!

คำตอบ:


296

กำหนด

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

ใช้

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

หรือ

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

ฟังก์ชั่นด้านบนใช้ประโยชน์จาก Swuple tuples เพื่อคืนค่าสามค่าในครั้งเดียว คุณปรับโครงสร้าง tuple โดยใช้let (var, ...)ไวยากรณ์หรือสามารถเข้าถึงสมาชิก tuple แต่ละรายการได้ถ้าต้องการ

หากคุณต้องการพิมพ์ออกมาด้วยคำHoursอื่น ๆ ให้ใช้ดังนี้:

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

โปรดทราบว่าการดำเนินงานดังกล่าวข้างต้นsecondsToHoursMinutesSeconds()สำหรับIntข้อโต้แย้ง ถ้าคุณต้องการDoubleรุ่นที่คุณจะต้องตัดสินใจสิ่งที่มีค่ากลับมามี - อาจจะหรืออาจจะเป็น(Int, Int, Double) (Double, Double, Double)คุณสามารถลองสิ่งที่ชอบ:

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
(seconds % 3600) % 60สามารถปรับค่าสุดท้ายให้seconds % 60เป็น ไม่จำเป็นต้องแตกชั่วโมงก่อน
zisoft

@GoZoner - ฉันไม่สามารถรับฟังก์ชั่น printSecondsToHoursMinutesSeconds ให้ทำงานได้อย่างถูกต้อง นี่คือสิ่งที่ฉันมีในสนามเด็กเล่น แต่พิมพ์วินาทีถึงชั่วโมงนาทีวินาทีไม่ได้คืนอะไรเลย: นำเข้า UIKit func secondsToHoursMinutes วินาที (วินาที: Int) -> (Int, Int, Int) {return (วินาที / 3600, (วินาที% 3600) / 60, (วินาที % 3600)% 60)} let (h, m, s) = secondsToHoursMinutesSeconds (27005) func printSecondsToHoursMinutesSeconds (วินาที: Int) -> () {let (h, m, s) = secondsToHoursMinutes วินาที (วินาที) ) ชั่วโมง, (m) นาที, วินาที (s) วินาที ")}
Joe

printSecondstoHoursMinutesSeconds()ไม่ส่งคืนสิ่งใด (ดู-> ()ประเภทการคืนค่าในการประกาศฟังก์ชัน) ฟังก์ชันพิมพ์บางสิ่ง ซึ่งไม่ปรากฏในสนามเด็กเล่น หากคุณต้องการให้ส่งคืนสิ่งนั้นให้พูด a Stringแล้วกำจัดการprintln()เรียกและแก้ไขประเภทการส่งคืนของฟังก์ชัน
GoZoner

@GoZoner - เพียงแค่คำถามด่วนในไวยากรณ์ของคุณด้านบน ฉันจะประกาศว่า 27005 ในตัวแปรได้อย่างไร ตอนนี้ฉันกำลังทำงานกับเครื่องมือเพื่อทำให้เท้าของฉันเปียกด้วยความรวดเร็ว ฉันมีค่าคงที่ที่แสดงจำนวนวินาที (สร้างขึ้นหลังจากการคำนวณพื้นฐานของฉัน) ให้ cocSeconds = cocMinutes * 60. (cocSeconds คือสิ่งที่ฉันต้องการใช้แทน 27005) ฉันคิดว่าปัญหาที่ฉันมีคือ cocSeconds เป็นสองเท่าและในไวยากรณ์ของคุณคุณกำลังใช้ Ints ฉันจะไปปรับรหัสนี้เพื่อวางตัวแปรแทนที่ 27005 อย่างไร ขอบคุณมากล่วงหน้า !!!
โจ

วิธีการแก้ปัญหาที่ฉันให้สำหรับIntประเภทเพราะธรรมชาติของ/และ%ฟังก์ชั่น นั่นคือส่วนที่/ลดลง Doubleรหัสเดียวกันจะไม่ทำงาน โดยเฉพาะ 2 == 13/5 แต่ 2.6 == 13.0 / 5 Doubleดังนั้นคุณจะต้องมีการดำเนินงานที่แตกต่างกันสำหรับ ฉันได้อัปเดตคำตอบของฉันพร้อมด้วยหมายเหตุเกี่ยวกับสิ่งนี้
GoZoner

171

ใน macOS 10.10+ / iOS 8.0+ (NS)DateComponentsFormatterถูกนำเสนอเพื่อสร้างสตริงที่อ่านได้

จะพิจารณาสถานที่และภาษาของผู้ใช้

let interval = 27005

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

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

รูปแบบหน่วยที่มีอยู่positional, abbreviated, short, full, และspellOutbrief

สำหรับข้อมูลเพิ่มเติมโปรดอ่านเอกสารประกอบ


19
การใช้formatter.unitsStyle = .positionalให้สิ่งที่ฉันต้องการอย่างแน่นอน (ซึ่งก็คือ7:30:05)! คำตอบที่ดีที่สุด IMO
แซม

11
และคุณสามารถเพิ่มศูนย์ `` `formatter.zeroFormattingBehavior = .pad` ``
Eduardo Irias

วิธีการรับในทางกลับกันนี้ นั่นคือวิธีการแปลงชั่วโมงนาทีเป็นวินาที
Angel F Syrus

1
@AngelFSyrus เพียงhours * 3600 + minutes * 60
Vadian

59

จากคำตอบของ Vadianฉันเขียนส่วนขยายที่ใช้Double(ซึ่งTimeIntervalเป็นนามแฝงประเภท) และแยกสตริงที่จัดรูปแบบตามเวลา

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

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

@MaksimKniazev โดยปกติค่าเชิงเวลาจะถูกแสดงด้วยDoublesใน Swift
Adrian

@ เอเดรียขอบคุณสำหรับการขยาย ฉันชอบ. Unititional Style แต่ฉันต้องการที่จะแสดงเช่น: 9 วินาทีเป็น "00:09" แทน "9", 1 นาที 25 วินาทีเป็น "01:25" แทน "1:25" ฉันสามารถคำนวณได้ด้วยตนเองโดยใช้ค่า Double และฉันสงสัยว่ามีวิธีรวมเข้ากับส่วนขยายหรือไม่ ขอบคุณ.
Vetuka

FYI: ถ้าคุณต้องการที่จะเก็บ 0s ก่อนค่าตัวเลขหลักเดียว (หรือถ้ามีค่าเป็น 0) formatter.zeroFormattingBehavior = .padคุณจะต้องเพิ่มนี้ สิ่งนี้จะทำให้เรา:3660.asString(style: .positional) // 01:01:00
Moucheg

27

ผมได้สร้าง Mashup ของคำตอบที่มีอยู่เพื่อให้ง่ายต่อทุกอย่างและลดปริมาณของรหัสที่จำเป็นสำหรับสวิฟท์ 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)"
}

การใช้งาน:

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

พิมพ์:

00:01:40


5
จากมุมมองของฉันการเพิ่มการปิดไม่ได้ลดความซับซ้อนอะไรจริงๆ มีเหตุผลที่ดีสำหรับการปิดหรือไม่?
derpoliuk

@derpoliuk ฉันต้องการการปิดสำหรับความต้องการเฉพาะของฉันในแอพของฉัน
David Seek

24

นี่เป็นวิธีที่มีโครงสร้าง / ยืดหยุ่นมากขึ้น: (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)

การมีวิธีการเช่นนี้จะช่วยให้เพิ่มความสะดวกในการแยกวิเคราะห์เช่นนี้:

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

ควรสังเกตว่าวิธีการที่ใช้ Integer ล้วนๆไม่ได้คำนึงถึงการกระโดดข้ามวัน / วินาที หากกรณีการใช้งานมีการจัดการกับวันที่ / เวลาจริงวันที่และปฏิทินควรจะใช้


คุณช่วยเพิ่มmonthการใช้งานของคุณได้ไหม? ขอบคุณล่วงหน้า!
ixany

3
คุณควรใช้ NSCalendar (ปฏิทิน) เพื่ออะไรแบบนั้น
NoLongerContributingToSE

คุณสามารถแทนที่return number < 10 ? "0\(number)" : "\(number)"โดยใช้ตัวจัดรูปแบบสตริงreturn String(format: "%02d", number)ซึ่งจะเพิ่มศูนย์โดยอัตโนมัติเมื่อจำนวนต่ำกว่า 10
ต่อเนื่อง

19

ในสวิฟต์ 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)
    }

เพื่อเรียกฟังก์ชั่น

    timeString(time: TimeInterval(i))

จะกลับมาอีก02:44:57


สุดยอด! สิ่งที่ฉันต้องการ ฉันเปลี่ยน 9897 สำหรับตัวแปร Int และได้ผลลัพธ์ที่ต้องการ ขอบคุณ!
David_2877

13

สวิฟต์ 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 คืออะไร Xcode ไม่รู้จักสำหรับฉัน
Alfi

10

นี่คือการใช้งานง่าย ๆ ใน 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

โซลูชัน SWIFT 3.0 อ้างอิงคร่าวๆตามที่กล่าวข้างต้นโดยใช้ส่วนขยาย

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 เรียกมันว่าเป็นแบบนี้หรือเปล่า?

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

8

ฉันตอบคำถามที่คล้ายกันแล้ว แต่คุณไม่จำเป็นต้องแสดงผลเป็นมิลลิวินาที ดังนั้นโซลูชันของฉันต้องใช้ iOS 10.0, tvOS 10.0, watchOS 3.0 หรือ macOS 10.12

คุณควรโทรfunc convertDurationUnitValueToOtherUnits(durationValue:durationUnit:smallestUnitDuration:)จากคำตอบที่ฉันพูดถึงแล้วที่นี่:

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

สวิฟท์ 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)"
    }
}

การใช้งาน:

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

3

ตามคำตอบของGoZonerฉันได้เขียนส่วนขยายเพื่อให้ได้รับการจัดรูปแบบเวลาตามชั่วโมงนาทีและวินาที:

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

นี่คือสิ่งที่ฉันใช้สำหรับเครื่องเล่นเพลงใน Swift 4+ ฉันกำลังแปลงวินาทีIntเป็นรูปแบบ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)
    }
}

ใช้แบบนี้:

print(7903.toAudioString)

เอาท์พุท: 2:11:43


3

คำตอบของ @ r3dm4n ยอดเยี่ยมมาก อย่างไรก็ตามฉันต้องการชั่วโมงด้วย ในกรณีที่คนอื่นต้องการด้วยที่นี่ก็คือ:

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

รหัสล่าสุด: XCode 10.4 Swift 5

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

2

Swift 5 & String Response, ในรูปแบบที่แสดงได้

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

การใช้งาน:

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

1

วิธีที่ง่ายที่สุด 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)

มันอาจจะเป็นldสองเท่าแทนที่จะdเป็น int
Nik Kov

1

NSTimeIntervalเป็นDoubleสิ่งที่ต้องทำทำมันมีนามสกุล ตัวอย่าง:

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

ฉันไปข้างหน้าและสร้างการปิดสำหรับเรื่องนี้ (ใน Swift 3)

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

สิ่งนี้จะให้ m = 4 และ s = 59 ดังนั้นคุณสามารถจัดรูปแบบตามที่คุณต้องการ แน่นอนคุณอาจต้องการเพิ่มชั่วโมงเช่นกันหากไม่มีข้อมูลเพิ่มเติม


0

Swift 4 ฉันใช้ส่วนขยายนี้

 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

คำตอบของ neekไม่ถูกต้อง

นี่คือรุ่นที่ถูกต้อง

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

อีกวิธีหนึ่งคือการแปลงวินาทีให้เป็นวันที่และใช้ส่วนประกอบเช่นวินาทีนาทีและชั่วโมงจากวันที่นั้นเอง วิธีนี้มีข้อ จำกัด จนถึง 23:59:59 น

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.