Swift - Chuyển đổi số nguyên thành Giờ / Phút / Giây


131

Tôi có một câu hỏi cơ bản (phần nào?) Về chuyển đổi thời gian trong Swift .

Tôi có một số nguyên mà tôi muốn chuyển đổi thành Giờ / Phút / Giây.

Ví dụ: Int = 27005 sẽ cho tôi:

7 Hours  30 Minutes 5 Seconds

Tôi biết làm thế nào để làm điều này trong PHP, nhưng than ôi, swift không phải là PHP :-)

Bất kỳ lời khuyên về cách tôi có thể đạt được điều này trong swift sẽ là tuyệt vời! Cảm ơn bạn trước!

Câu trả lời:


296

Định nghĩa

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

Sử dụng

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

hoặc là

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

Hàm trên sử dụng bộ dữ liệu Swift để trả về ba giá trị cùng một lúc. Bạn cấu trúc bộ dữ liệu bằng cách sử dụnglet (var, ...) cú pháp hoặc có thể truy cập các thành viên bộ dữ liệu riêng lẻ nếu cần.

Nếu bạn thực sự cần in nó ra bằng các từ Hoursvv thì hãy sử dụng cái gì đó như thế này:

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

Lưu ý rằng việc thực hiện các secondsToHoursMinutesSeconds()công việc trên cho các Intđối số. Nếu bạn muốn có một Doublephiên bản, bạn sẽ cần phải quyết định giá trị trả về là gì - có thể (Int, Int, Double)hoặc có thể (Double, Double, Double). Bạn có thể thử một cái gì đó như:

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
Giá trị cuối cùng (seconds % 3600) % 60có thể được tối ưu hóa seconds % 60. Không cần phải trích xuất giờ đầu tiên.
zisoft

@GoZoner - tôi dường như không thể có được chức năng printSecondsToHoursMinutesSeconds để hoạt động bình thường. Đây là những gì tôi có trong một sân chơi, nhưng printSecondsToHoursMinutesSeconds không trả lại bất cứ thứ gì: nhập UIKit func giâyToHoursMinutesSeconds (giây: Int) -> (Int, Int, Int) {return (giây / 3600, (giây% 3600) / giây % 3600)% 60)} let (h, m, s) = giâyToHoursMinutesSeconds (27005) func printSecondsToHoursMinutesSeconds (giây: Int) -> () {let (h, m, s) = giâyToHoursMinutes (giây) ) Giờ, (m) Phút, (s) giây ")}
Joe

printSecondstoHoursMinutesSeconds()không trả về bất cứ điều gì (xem -> ()kiểu trả về trong khai báo hàm). Hàm in một cái gì đó; mà không xuất hiện trong một Sân chơi. Nếu bạn muốn nó trả về một cái gì đó, hãy nói Stringsau đó loại bỏ println()cuộc gọi và sửa kiểu trả về của hàm.
GoZoner

@GoZoner - chỉ là một câu hỏi nhanh trong cú pháp của bạn ở trên. Làm thế nào tôi có thể khai báo rằng 27005 trong một biến? Tôi đang làm việc trên một công cụ ngay bây giờ để có được đôi chân ướt át. Tôi có một hằng số hiển thị số giây (được tạo sau các tính toán cơ bản của tôi). hãy để cocSeconds = cocMinutes * 60. (cocSeconds là thứ tôi muốn sử dụng thay cho 27005.) Tôi nghĩ rằng vấn đề tôi gặp phải là cocSeconds là một cú đúp và trong cú pháp của bạn, bạn đang sử dụng Ints. Làm thế nào tôi có thể điều chỉnh mã này để đặt một biến thay cho 27005? Cảm ơn trước!!!
Joe

Các giải pháp tôi đã làm việc cho Intloại vì bản chất của /%chức năng. Đó là /giảm phần phe phái. Các mã tương tự sẽ không làm việc cho Double. Cụ thể 2 == 13/5 nhưng 2.6 == 13.0 / 5. Vì vậy, bạn sẽ cần một thực hiện khác nhau cho Double. Tôi đã cập nhật câu trả lời của tôi với một lưu ý về điều này.
GoZoner

171

Trong macOS 10.10+ / iOS 8.0+ (NS)DateComponentsFormatterđã được giới thiệu để tạo chuỗi có thể đọc được.

Nó xem xét ngôn ngữ của người dùng và ngôn ngữ.

let interval = 27005

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

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

Các phong cách đơn vị sẵn có positional, abbreviated, short, full, spellOutbrief.

Để biết thêm thông tin vui lòng đọc documenation .


19
Sử dụng formatter.unitsStyle = .positionalcho chính xác những gì tôi muốn (đó là 7:30:05)! Câu trả lời hay nhất IMO
Sam

11
Và bạn có thể thêm số không `` `formatter.zeroFormattedBehavior = .pad` ``
Eduardo Irias

Làm thế nào để có được ngược lại của điều này. Đó là cách chuyển đổi Giờ, Phút thành giây
Angel F Syrus

1
@AngelFSyrus Đơn giảnhours * 3600 + minutes * 60
vadian

59

Dựa trên câu trả lời của Vadian , tôi đã viết một phần mở rộng lấy một Double(trong đó TimeIntervallà bí danh loại) và tạo ra một chuỗi được định dạng theo thời gian.

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

Dưới đây là các DateComponentsFormatter.UnitsStyletùy chọn khác nhau trông như thế nào:

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 Thông thường các giá trị định hướng theo thời gian được biểu thị bằng DoublesSwift.
Adrian

@Adrian cảm ơn bạn đã gia hạn. Tôi thích đơn vị .Spose điều kiện, tuy nhiên tôi muốn hiển thị tức là: 9 giây là "00:09" thay vì "9", 1 phút 25 giây là "01:25" thay vì "1:25". Tôi có thể đạt được tính toán này một cách thủ công, dựa trên giá trị Double và tôi đã tự hỏi liệu có cách nào để kết hợp vào chính phần mở rộng không? Cảm ơn bạn.
Vetuka

FYI: nếu bạn muốn giữ 0 trước một giá trị một chữ số (hoặc đơn giản nếu giá trị bằng 0), bạn cần thêm giá trị này formatter.zeroFormattingBehavior = .pad. Điều này sẽ cho chúng ta:3660.asString(style: .positional) // 01:01:00
Moucheg

27

Tôi đã xây dựng một bản hòa trộn các câu trả lời hiện có để đơn giản hóa mọi thứ và giảm số lượng mã cần thiết cho 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)"
}

Sử dụng:

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

Bản in:

00:01:40


5
Từ quan điểm của tôi, việc thêm đóng không thực sự đơn giản hóa bất cứ điều gì. Có bất kỳ lý do tốt để đóng cửa?
derpoliuk

@derpoliuk Tôi cần đóng cửa cho các nhu cầu cụ thể của mình trong ứng dụng của mình
David Seek

24

Đây là một cách tiếp cận có cấu trúc / linh hoạt hơn: (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)

Có một cách tiếp cận như thế này cho phép thêm phân tích cú pháp tiện lợi như thế này:

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

Cần lưu ý rằng các cách tiếp cận hoàn toàn dựa trên Integer không tính đến ngày nhuận / giây. Nếu trường hợp sử dụng đang xử lý ngày / lần thực NgàyLịch nên được sử dụng.


Bạn có thể vui lòng thêm monthvào thực hiện của bạn? Cảm ơn trước!
ixany

3
Bạn nên sử dụng NSCalWiki (Lịch) cho những thứ tương tự.
NoLongerContributionToSE

Bạn có thể thay thế return number < 10 ? "0\(number)" : "\(number)"bằng cách sử dụng trình định dạng chuỗi return String(format: "%02d", number)tự động thêm số 0 khi số dưới 10
Continuum

19

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

Để gọi chức năng

    timeString(time: TimeInterval(i))

Sẽ trở lại 02:44:57


Tuyệt vời! Chỉ cần những gì tôi yêu cầu. Tôi đã thay đổi 9897 cho một biến Int và nhận được kết quả mong muốn. Cảm ơn bạn!
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)
}

Cắt ngắnRemainder là gì? Xcode không nhận ra nó cho tôi.
Alfi

10

Đây là một triển khai đơn giản khác trong 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

Giải pháp SWIFT 3.0 dựa trên phần mở rộng.

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

  }
}

Sử dụng nó với AVPlayer gọi nó như thế này?

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

8

Tôi đã trả lời cho câu hỏi tương tự , tuy nhiên bạn không cần hiển thị mili giây trong kết quả. Do đó giải pháp của tôi yêu cầu iOS 10.0, tvOS 10.0, watchOS 3.0 hoặc macOS 10.12.

Bạn nên gọi func convertDurationUnitValueToOtherUnits(durationValue:durationUnit:smallestUnitDuration:)từ câu trả lời mà tôi đã đề cập ở đây:

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

Sử dụng:

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

3

Theo câu trả lời của GoZoner, tôi đã viết một Tiện ích mở rộng để có được thời gian được định dạng theo giờ, phút và giây:

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

Đây là những gì tôi sử dụng cho Trình phát nhạc của mình trong Swift 4+. Tôi đang chuyển đổi giây Int sang định dạng Chuỗi có thể đọc được

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

Sử dụng như thế này:

print(7903.toAudioString)

Đầu ra: 2:11:43


3

Câu trả lời của @ r3dm4n thật tuyệt. Tuy nhiên, tôi cũng cần giờ trong đó. Chỉ trong trường hợp người khác cũng cần ở đây:

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

Mã mới nhất: XCode 10,4 Swift 5

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

2

Swift 5 & String Đáp ứng, ở định dạng có thể trình bày

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

Sử dụng:

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

1

Cách đơn giản nhất 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)

Nó có thể là ldgấp đôi thay vì dcho int.
Nik Kov

1

NSTimeIntervalDoublelàm điều đó với phần mở rộng. Thí dụ:

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

Tôi đã tiếp tục và tạo ra một kết thúc cho việc này (trong Swift 3).

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

Điều này sẽ cho m = 4 và s = ​​59. Vì vậy, bạn có thể định dạng theo ý muốn. Tất nhiên bạn có thể muốn thêm giờ, nếu không có thêm thông tin.


0

Swift 4 Tôi đang sử dụng tiện ích mở rộng này

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

kế thừa

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

0

Câu trả lời của Neek không đúng.

đây là phiên bản chính xác

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

Một cách khác sẽ là chuyển đổi giây thành ngày và lấy các thành phần tức là giây, phút và giờ kể từ ngày. Giải pháp này có giới hạn chỉ đến 23:59:59

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.