Swift - Перетворення цілого числа в години / хвилини / секунди


131

У мене є (дещо?) Основне питання щодо перерахунку часу в Swift .

У мене є ціле число, яке я хотів би перетворити на години / хвилини / секунди.

Приклад: 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)

Вищенаведена функція використовує кортежі Swift для повернення трьох значень одночасно. Ви знищуєте кортеж за допомогоюlet (var, ...) синтаксису або можете отримати доступ до окремих членів кортежу, якщо це необхідно.

Якщо вам справді потрібно роздрукувати його словами 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 не працює належним чином. Це те, що у мене є на ігровому майданчику, але printSecondsToHoursMinutesSeconds не повертає нічого: імпорт UIKit func секундToHoursMinutesSeconds (секунд: Int) -> (Int, Int, Int) {return (секунд / 3600, (секунди% 3600) / 60, (секунд % 3600)% 60)} let (h, m, s) = секундToHoursMinutesSeconds (27005) func printSecondsToHoursMinutesSeconds (секунд: Int) -> () {let (h, m, s) = секундToHoursMinutesSeconds (секунди) println ("(h ) Години, (м) Хвилини, секунди секунд ")}
Джо

printSecondstoHoursMinutesSeconds()нічого не повертає (див. -> ()тип повернення в декларації функції). Функція щось друкує; який не відображається на дитячому майданчику. Якщо ви хочете, щоб він щось повернув, скажіть 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, spellOutі brief.

Для отримання додаткової інформації, будь ласка, прочитайте документацію .


19
Використання formatter.unitsStyle = .positionalдає саме те, що я хочу (що є 7:30:05)! Найкраща відповідь ІМО
Сем

11
І ви можете додати нульовий `` `formatter.zeroFormattingBehavior = .pad` ``
Eduardo Irias

Як отримати навпаки цього. Ось як перетворити Години, Хвилини на секунди
Ангел Ф

1
@AngelFSyrus Простоhours * 3600 + minutes * 60
вадіан

59

Спираючись на відповідь Вадіана , я написав розширення, яке бере 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 дякую за розширення. Мені подобається .позиційний UnitStyle, проте я хотів би відобразити, тобто: 9 секунд як "00:09" замість "9", 1 хв 25 секунд як "01:25" замість "1:25". Я в змозі досягти цього обчислення вручну, виходячи з подвійного значення, і мені було цікаво, чи є спосіб включити до самого розширення? Дякую.
Ветука

FYI: якщо ви бажаєте зберегти 0 перед однозначним значенням (або просто, якщо значення дорівнює 0), вам потрібно додати це formatter.zeroFormattingBehavior = .pad. Це дало б нам:3660.asString(style: .positional) // 01:01:00
Moucheg

27

Я створив перебір існуючих відповідей, щоб спростити все та зменшити кількість коду, необхідного для 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)"
}

Використання:

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 Мені потрібно закриття для моїх конкретних потреб у моєму додатку
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

Слід зазначити, що суто підходи, що базуються на цілісі, не враховують високосний день / секунди. Якщо випадок використання має справу з реальними датами / часом, слід використовувати дату та календар .


Не могли б ви додати monthдо своєї реалізації? Спасибі заздалегідь!
ixany

3
Ви повинні використовувати NSCalendar (Календар) для чогось подібного.
NoLongerContributingToSE

Ви можете замінити return number < 10 ? "0\(number)" : "\(number)", використовуючи формат-формат, return String(format: "%02d", number)який автоматично додає нуль, коли число нижче 10
Продовження

19

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

Для виклику функції

    timeString(time: TimeInterval(i))

повернуся 2: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)
}

Що таке обрізальний ремідер? Xcode не розпізнає це для мене.
Альфі

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

Найпростіший спосіб:

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подвійний замість dint.
Нік Ков

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

використання

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.