Swift - 整数转换为小时/分钟/秒

215

我有一个(有点基础的?)关于在Swift中进行时间转换的问题。

我有一个整数,我想将其转换为小时/分钟/秒。

例如: Int = 27005 将给我:

7 Hours  30 Minutes 5 Seconds

我知道如何在PHP中做到这一点,但是可惜,Swift不是PHP。

25个回答

402

定义

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

24
最后一个值(seconds % 3600) % 60可以优化为seconds % 60,不需要先提取小时。 - zisoft
@GoZoner - 我似乎无法使printSecondsToHoursMinutesSeconds函数正常工作。这是我在playground中的代码,但printSecondsToHoursMinutesSeconds没有返回任何内容:import UIKitfunc secondsToHoursMinutesSeconds (seconds : Int) -> (Int, Int, Int) { return (seconds / 3600, (seconds % 3600) / 60, (seconds % 3600) % 60) } let (h,m,s) = secondsToHoursMinutesSeconds(27005)func printSecondsToHoursMinutesSeconds (seconds:Int) -> () { let (h, m, s) = secondsToHoursMinutesSeconds (seconds) println ("(h) 小时, (m) 分钟, (s) 秒") } - Joe
printSecondstoHoursMinutesSeconds() 不返回任何内容(请参见函数声明中的 -> () 返回类型)。该函数会打印一些东西,但在 Playground 中不会显示出来。如果你想让它返回某些内容,比如一个 String,那么就要消除 println() 调用,并修复函数的返回类型。 - GoZoner
@GoZoner - 你好,我有一个问题想请教一下你的语法。如果我想把27005声明为一个变量,应该怎么做呢?我正在开发一个工具,用Swift来熟悉它。我有一个常量,显示了经过基本计算后生成的秒数。let cocSeconds = cocMinutes * 60. (我想用cocSeconds代替27005)我认为我遇到的问题是cocSeconds是一个double类型,在你的语法中,你使用的是Int类型。我该如何调整这段代码,以便在27005的位置上放置一个变量呢?非常感谢您提前的帮助!!! - Joe
我提供的解决方案适用于Int类型,因为/函数的性质。也就是说,/会删除小数部分。相同的代码对于Double不起作用。具体而言,2 == 13/5,但2.6 == 13.0/5。因此,您需要针对Double进行不同的实现。我已经在我的答案中更新了这个说明。 - GoZoner

279
在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)

可用的单位样式包括positionalabbreviatedshortfullspellOutbrief

欲了解更多信息,请阅读文档


47
使用 formatter.unitsStyle = .positional 就能得到我想要的结果(即 7:30:05)!在我看来这是最好的答案。 - Sam
23
并且你可以添加零。formatter.zeroFormattingBehavior = .pad - Eduardo Irias
如何获取相反的结果。也就是如何将小时、分钟转换为秒。 - Angel F Syrus
1
@AngelFSyrus 简单地使用 hours * 3600 + minutes * 60 - vadian
如果您的秒数少于一分钟,特别是在较短的样式中,您可能需要这个:formatter.zeroFormattingBehavior = [ .pad ] - multitudes

120

Vadian的答案基础上,我编写了一个扩展,它接受一个Double(其中TimeInterval是一个类型别名)并输出格式化为时间的字符串。

extension Double {
  func asString(style: DateComponentsFormatter.UnitsStyle) -> String {
    let formatter = DateComponentsFormatter()
    formatter.allowedUnits = [.hour, .minute, .second, .nanosecond]
    formatter.unitsStyle = style
    return formatter.string(from: self) ?? ""
  }
}

下面是各种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

通常在Swift中,时间取向的值由Doubles表示。 - Adrian
@Adrian 谢谢您提供的扩展。我喜欢.positional UnitStyle,但是我想要显示例如:9秒为“00:09”,而不是“9”,1分25秒为“01:25”,而不是“1:25”。我可以通过手动计算基于Double值来实现这一点,但我想知道是否有一种方法将其纳入扩展本身?谢谢。 - Vetuka
6
如果您想在单个数字值前保留0(或者该值本身是0),则需要添加formatter.zeroFormattingBehavior = .pad。这样,我们将得到: 3660.asString(style: .positional) // 01:01:00 - Moumou
请注意,DateComponentsFormatter 在 Linux 上不可用。 - Xander Dunn
@Adrian,您可以将最后两行替换为return formatter.string(from: self) ?? "" - budiDino
Swift5 中的纳秒级别暂停 - slboat

40

在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


太棒了!正是我需要的。我将9897更改为Int变量,并获得了所需的结果。谢谢! - David_2877
在Swift 5.3中,这对我不起作用。我发送了一个217368毫秒的TimeInterval值,它返回60:22:48。217368毫秒是10:02。 - SouthernYankee65
@SouthernYankee65 请传递秒数,而不是毫秒。在Swift 5.3中对我有效。 - Akash Neeli

31

我已经建立了一个混搭现有答案的东西,以简化所有内容并减少所需的代码量,适用于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


6
在我看来,添加闭包并没有真正简化任何事情。闭包存在的好处是什么? - derpoliuk
@derpoliuk 我需要闭包来满足我应用程序中的特定需求。 - David Seek

28

以下是一种更加有结构和灵活的方法:(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

需要注意的是,纯整数方法不考虑闰年/闰秒。如果使用案例涉及实际日期/时间,应该使用DateCalendar


请问您能否在您的实现中加入“月份”?非常感谢! - ixany
3
你应该使用NSCalendar(日历)来完成这样的操作。 - GetSwifty
1
你可以使用字符串格式化器 return String(format: "%02d", number) 来替换 return number < 10 ? "0\(number)" : "\(number)",当数字小于10时,它会自动添加一个零。 - Continuum

20

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"

16

Xcode 12.1. Swift 5

DateComponentsFormatter:一个可以创建字符串表述的格式化器,通过使用 unitsStyle 可以得到你想要的字符串并指定 allowedUnits。

例如:对于 unitsStyle:: 10000 秒的输出为:

  1. full = "2 小时,46 分钟,49 秒"
  2. positional = "2:46:40"
  3. abbreviated = "2小时 46分 40秒"
  4. spellOut = "两小时四十六分钟四十秒”
  5. short = "2小时 46分钟 40秒"
  6. brief = "2小时 46分钟 40秒"

易于使用:

 let time = convertSecondsToHrMinuteSec(seconds: 10000)


func convertSecondsToHrMinuteSec(seconds:Int) -> String{
     let formatter = DateComponentsFormatter()
     formatter.allowedUnits = [.hour, .minute, .second]
     formatter.unitsStyle = .full
    
     let formattedString = formatter.string(from:TimeInterval(seconds))!
     print(formattedString)
     return formattedString
    }

14

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

什么是 truncatingRemainder?我的 Xcode 不认识它。 - Ahmadreza
您可以在此处阅读有关截断余数的更多信息:https://developer.apple.com/documentation/swift/double/2885641-truncatingremainder - r3dm4n

13

这里是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
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接