Swift - целочисленное преобразование в часы / минуты / секунды

133

У меня есть (несколько?) Основной вопрос относительно преобразования времени в Swift .

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

Пример: Int = 27005 даст мне:

7 Hours  30 Minutes 5 Seconds

Я знаю, как это сделать в PHP, но, увы, swift - это не PHP :-)

Любые советы о том, как я могу достичь этого быстро, были бы фантастическими! Заранее спасибо!

Джо
источник

Ответы:

298

определять

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)
}
GoZoner
источник
14
Последнее значение (seconds % 3600) % 60можно оптимизировать до seconds % 60. Не нужно сначала извлекать часы.
zisoft
@GoZoner - похоже, я не могу заставить функцию printSecondsToHoursMinutesSeconds работать правильно. Это то, что у меня есть на игровой площадке, но printSecondsToHoursMinutesSeconds ничего не возвращает: import UIKit func secondsToHoursMinutesSeconds (секунды: Int) -> (Int, Int, Int) {return (секунды / 3600, (секунды% 3600) / 60, (секунды) % 3600)% 60)} let (h, m, s) = secondsToHoursMinutesSeconds (27005) func printSecondsToHoursMinutesSeconds (секунды: Int) -> () {let (h, m, s) = secondsToHoursMinutesSeconds (секунды) println ("(h ) Часы, (м) Минуты, (с) Секунды »)}
Джо
printSecondstoHoursMinutesSeconds()ничего не возвращает (см. -> ()тип возвращаемого значения в объявлении функции). Функция что-то печатает; который не отображается на игровой площадке. Если вы хотите, чтобы он что-то возвращал, скажите a, Stringзатем устраните println()вызов и исправьте тип возвращаемого значения функции.
GoZoner
@GoZoner - просто вопрос в синтаксисе выше. Как мне объявить это 27005 в переменной? Я сейчас работаю над инструментом, чтобы намочить ноги с Swift. У меня есть константа, отображающая количество секунд (сгенерированная после моих основных вычислений). let cocSeconds = cocMinutes * 60. (cocSeconds - это то, что я хочу использовать вместо 27005.) Я думаю, что у меня проблема в том, что cocSeconds является двойным, и в вашем синтаксисе вы используете Ints. Как мне изменить этот код, чтобы вместо 27005 поставить переменную? Огромное спасибо заранее!!!
Joe
Решение , которое я дал работает Intтип из - за характер из /и %функций. То есть /выпадает фракционная часть. Тот же код не будет работать Double. В частности, 2 == 13/5, но 2,6 == 13,0 / 5. Поэтому вам понадобится другая реализация для Double. Я обновил свой ответ примечанием по этому поводу.
GoZoner
174

В 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.

Для получения дополнительной информации прочтите документацию .

vadian
источник
20
Использование formatter.unitsStyle = .positionalдает именно то, что я хочу (то есть 7:30:05)! Лучший ответ IMO
Sam
12
И вы можете добавить ноль `` formatter.zeroFormattingBehavior = .pad ''
Эдуардо Ириас
Как получить наоборот. Вот как преобразовать часы, минуты в секунды
Angel F Syrus
1
@AngelFSyrus Simplyhours * 3600 + minutes * 60
vadian
60

Основываясь на ответе Вадиана , я написал расширение, которое принимает DoubleTimeIntervalтом числе псевдоним типа) и выводит строку, отформатированную как время.

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.
Адриан
@ Адриан, спасибо за расширение. Мне нравится .positional UnitStyle, однако я хотел бы отображать то есть: 9 секунд как «00:09» вместо «9», 1мин 25 секунд как «01:25» вместо «1:25». Я могу выполнить это вычисление вручную на основе значения Double, и мне было интересно, есть ли способ включить его в само расширение? Спасибо.
Vetuka 07
К вашему сведению: если вы хотите сохранить нули перед однозначным значением (или просто, если значение равно 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
@derpoliuk Мне нужно было закрытие для моих конкретных нужд в моем приложении
Дэвид
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

Следует отметить, что подходы, основанные исключительно на целых числах, не принимают во внимание високосные дни / секунды. Если вариант использования имеет дело с реальными датами / временем, следует использовать дату и календарь .

NoLongerContributingToSE
источник
Не могли бы вы добавить monthк своей реализации? Заранее спасибо!
ixany 05
3
Вы должны использовать NSCalendar (Календарь) для чего-то подобного.
NoLongerContributingToSE 05
Вы можете заменить return number < 10 ? "0\(number)" : "\(number)", используя средство форматирования строк, return String(format: "%02d", number)которое автоматически добавляет ноль, когда число меньше 10
Continuum
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))

Вернусь 02:44:57

DialDT
источник
Superb! Именно то, что мне нужно. Я заменил 9897 на переменную Int и получил желаемые результаты. Спасибо!
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)
}
r3dm4n
источник
Что такое truncatingRemainder? 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
}
neeks
источник
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
user3069232
источник
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

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

Использование:

let seconds : Int = 119
print(seconds.secondsToTime()) // Result = "00:01:59"
ZAFAR007
источник
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"
xGoPox
источник
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)
}
Vetuka
источник
3

Последний код: XCode 10.4 Swift 5

extension Int {
    func timeDisplay() -> String {
        return "\(self / 3600):\((self % 3600) / 60):\((self % 3600) % 60)"
    }
}
Saranjith
источник
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)
Gamec
источник
Это может быть lddouble вместо 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 ""
    }
}

Useage

// assume myTimeInterval = 96460.397    
myTimeInteval.stringFromInterval() // 1d 2h 47m 40s 397ms
caesss
источник
0

ответ Ника неверен .

вот правильная версия

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

Wasim
источник