【问题标题】:conversion from NSTimeInterval to hour,minutes,seconds,milliseconds in swift快速从 NSTimeInterval 转换为小时、分钟、秒、毫秒
【发布时间】:2015-05-06 12:05:03
【问题描述】:

我的代码在这里:

func stringFromTimeInterval(interval:NSTimeInterval) -> NSString {

    var ti = NSInteger(interval)
    var ms = ti * 1000
    var seconds = ti % 60
    var minutes = (ti / 60) % 60
    var hours = (ti / 3600)

      return NSString(format: "%0.2d:%0.2d:%0.2d",hours,minutes,seconds,ms)
}

在输出中毫秒给出了错误的结果。请给出如何正确找到毫秒的想法。

【问题讨论】:

  • 由于 NSTimeInterval 通常不处理毫秒而是秒,我的问题是为什么“* 1000”,它应该总是 0。如果你的实现管理毫秒,它应该是“%1000” ,不是吗?
  • 是的,你是对的,它必须是 %1000。我想要准确的时间,这就是我使用毫秒的原因。
  • 当然 NSTimeInterval 处理几分之一秒(例如毫秒)。它是浮点类型,而不是整数。
  • @MatthiasBauch,@larme ya 但我的问题是当我发现两个时间之间的差异时,例如:1:36:22 和 1:36:24(hh:mm:ss 格式),它给出 00 :00:01 而不是 00:00:02。这就是为什么我认为它可能以毫秒为单位的变化。
  • 我也想要解决这个问题。

标签: ios swift nstimeinterval


【解决方案1】:

Swift 支持浮点数的余数计算,所以我们可以使用% 1

var ms = Int((interval % 1) * 1000)

如:

func stringFromTimeInterval(interval: TimeInterval) -> NSString {

  let ti = NSInteger(interval)

  let ms = Int((interval % 1) * 1000)

  let seconds = ti % 60
  let minutes = (ti / 60) % 60
  let hours = (ti / 3600)

  return NSString(format: "%0.2d:%0.2d:%0.2d.%0.3d",hours,minutes,seconds,ms)
}

结果:

stringFromTimeInterval(12345.67)                   "03:25:45.670"

斯威夫特 4:

extension TimeInterval{

        func stringFromTimeInterval() -> String {

            let time = NSInteger(self)

            let ms = Int((self.truncatingRemainder(dividingBy: 1)) * 1000)
            let seconds = time % 60
            let minutes = (time / 60) % 60
            let hours = (time / 3600)

            return String(format: "%0.2d:%0.2d:%0.2d.%0.3d",hours,minutes,seconds,ms)

        }
    }

用途:

self.timeLabel.text = player.duration.stringFromTimeInterval()

【讨论】:

  • 可能需要为小时添加“% 24”,即“let hours = (ti / 3600) % 24
  • ms 是错误的,我用 ti*1000 代替,否则我总是得到 0
  • '%' 不可用:对于浮点数,请改用 truncatingRemainder
  • 这是特定于语言环境的。在此处查看苹果的单元文档:developer.apple.com/videos/play/wwdc2020/10160 此响应也有副作用:此对TimeInterval 的扩展适用于所有Double 值,因为TimeIntervalDouble 的类型别名。这是文档声明:typealias TimeInterval = Double
【解决方案2】:

SWIFT 3 扩展

我认为这种方式更容易查看每个部分的来源,因此您可以更轻松地根据需要对其进行修改

extension TimeInterval {
    private var milliseconds: Int {
        return Int((truncatingRemainder(dividingBy: 1)) * 1000)
    } 

    private var seconds: Int {
        return Int(self) % 60
    } 

    private var minutes: Int {
        return (Int(self) / 60 ) % 60
    } 

    private var hours: Int {
        return Int(self) / 3600
    } 

    var stringTime: String {
        if hours != 0 {
            return "\(hours)h \(minutes)m \(seconds)s"
        } else if minutes != 0 {
            return "\(minutes)m \(seconds)s"
        } else if milliseconds != 0 {
            return "\(seconds)s \(milliseconds)ms"
        } else {
            return "\(seconds)s"
        }
    }
}

【讨论】:

  • 杰克这可能是一个很好的答案,但微积分并非 100% 正确:| 3599 返回-1s | 12601 返回 3h -29m 1s
  • 我建议进行修正微积分的编辑。再次感谢您的回答!
  • @PaulS。不知道,它可能还没有被批准(还没有?)
  • @PaulS。结果我的编辑建议被拒绝了,因为它“偏离了帖子的初衷”,但这里是链接:stackoverflow.com/review/suggested-edits/16940597
  • 为了避免微积分的麻烦,你也可以自己计算余数:interval = interval.rounded() let seconds = Int(interval) - (Int(interval / 60) * 60)跨度>
【解决方案3】:

Objective-C 中的等效项,基于 @matthias-bauch 的回答。

+ (NSString *)stringFromTimeInterval:(NSTimeInterval)timeInterval
{
    NSInteger interval = timeInterval;
    NSInteger ms = (fmod(timeInterval, 1) * 1000);
    long seconds = interval % 60;
    long minutes = (interval / 60) % 60;
    long hours = (interval / 3600);

    return [NSString stringWithFormat:@"%0.2ld:%0.2ld:%0.2ld,%0.3ld", hours, minutes, seconds, (long)ms];
}

【讨论】:

    【解决方案4】:

    适用于 iOS 8+、macOS 10.10+ 的 Swift 3 解决方案,如果时间的零填充无关紧要:

    func stringFromTime(interval: TimeInterval) -> String {
        let ms = Int(interval.truncatingRemainder(dividingBy: 1) * 1000)
        let formatter = DateComponentsFormatter()
        formatter.allowedUnits = [.hour, .minute, .second]
        return formatter.string(from: interval)! + ".\(ms)"
    }
    
    print(stringFromTime(interval: 12345.67)) // "3:25:45.670"
    

    【讨论】:

    • 如果你想显示零,请使用 formatter.zeroFormattingBehavior = .pad
    • @iLandes .pad 不会为最重要的部分(答案中的小时数)添加前导零。
    • @vadian 如果zeroFormattingBehavior = .pad@vadian 对我有用
    • @idrougge 再一次,不是最重要的组件。在示例中,即使使用.pad,您也不会得到"03:25:45.670"
    • 啊哈,现在我明白你的意思了。不,您不会使用 .pad 获得两位数的小时数。
    【解决方案5】:

    我认为这些答案中的大多数已经过时了,如果你想显示一个表示时间间隔的字符串,你应该总是使用 DateComponentsFormatter,因为它会为你处理填充和本地化。

    【讨论】:

    • 99% 的情况都是如此。当需要DateComponentsFormatter 不支持的NSCalendar.Unit(例如.nanosecond)时,使用其中一种方法会很有用。
    【解决方案6】:

    斯威夫特 4:

    extension TimeInterval{
    
            func stringFromTimeInterval() -> String {
    
                let time = NSInteger(self)
    
                let ms = Int((self.truncatingRemainder(dividingBy: 1)) * 1000)
                let seconds = time % 60
                let minutes = (time / 60) % 60
                let hours = (time / 3600)
    
                return String(format: "%0.2d:%0.2d:%0.2d.%0.3d",hours,minutes,seconds,ms)
    
            }
        }
    

    用途:

    self.timeLabel.text = player.duration.stringFromTimeInterval()
    

    【讨论】:

    • Int((self.truncatingRemainder(dividingBy: 1)) * 1000) 总是 0
    【解决方案7】:

    Swift 4,不使用.remainder(返回错误值):

    func stringFromTimeInterval(interval: Double) -> NSString {
    
        let hours = (Int(interval) / 3600)
        let minutes = Int(interval / 60) - Int(hours * 60)
        let seconds = Int(interval) - (Int(interval / 60) * 60)
    
        return NSString(format: "%0.2d:%0.2d:%0.2d",hours,minutes,seconds)
    }
    

    【讨论】:

      【解决方案8】:

      Swift 5。没有毫秒和一些条件格式(即,如果有 0 小时,则不显示小时)。

      extension TimeInterval{
      
      func stringFromTimeInterval() -> String {
      
          let time = NSInteger(self)
      
          let seconds = time % 60
          let minutes = (time / 60) % 60
          let hours = (time / 3600)
      
          var formatString = ""
          if hours == 0 {
              if(minutes < 10) {
                  formatString = "%2d:%0.2d"
              }else {
                  formatString = "%0.2d:%0.2d"
              }
              return String(format: formatString,minutes,seconds)
          }else {
              formatString = "%2d:%0.2d:%0.2d"
              return String(format: formatString,hours,minutes,seconds)
          }
      }
      }
      

      【讨论】:

        【解决方案9】:

        用于在 swift 2.0 中将小时和分钟转换为秒:

        ///RETORNA TOTAL DE SEGUNDOS DE HORA:MINUTOS
        func horasMinutosToSeconds (HoraMinutos:String) -> Int {
        
            let formatar = NSDateFormatter()
            let calendar = NSCalendar.currentCalendar()
            formatar.locale = NSLocale.currentLocale()
            formatar.dateFormat = "HH:mm"
        
            let Inicio = formatar.dateFromString(HoraMinutos)
            let comp = calendar.components([NSCalendarUnit.Hour, NSCalendarUnit.Minute], fromDate: Inicio!)
        
            let hora = comp.hour
            let minute = comp.minute
        
            let hours = hora*3600
            let minuts = minute*60
        
            let totseconds = hours+minuts
        
            return totseconds
        }
        

        【讨论】:

        • 一个简单的问题就这么复杂。
        • 值得一提的是,使用 DateFormatter 资源繁重,可以轻松避免。不过我不建议使用这种方法,它是一种有效的解决方案。
        • 我投了反对票,因为它没有格式化,葡萄牙语或西班牙语的 vars 和 let,Pascal 大小写的 var 和其他问题。这对我的眼睛不好
        【解决方案10】:

        @hixField 答案的 swift 3 版本,现在有几天和处理以前的日期:

        extension TimeInterval {
            func timeIntervalAsString(_ format : String = "dd days, hh hours, mm minutes, ss seconds, sss ms") -> String {
                var asInt   = NSInteger(self)
                let ago = (asInt < 0)
                if (ago) {
                    asInt = -asInt
                }
                let ms = Int(self.truncatingRemainder(dividingBy: 1) * (ago ? -1000 : 1000))
                let s = asInt % 60
                let m = (asInt / 60) % 60
                let h = ((asInt / 3600))%24
                let d = (asInt / 86400)
        
                var value = format
                value = value.replacingOccurrences(of: "hh", with: String(format: "%0.2d", h))
                value = value.replacingOccurrences(of: "mm",  with: String(format: "%0.2d", m))
                value = value.replacingOccurrences(of: "sss", with: String(format: "%0.3d", ms))
                value = value.replacingOccurrences(of: "ss",  with: String(format: "%0.2d", s))
                value = value.replacingOccurrences(of: "dd",  with: String(format: "%d", d))
                if (ago) {
                    value += " ago"
                }
                return value
            }
        
        }
        

        【讨论】:

          【解决方案11】:

          Swift 4(有范围检查 ~ 没有崩溃)

          import Foundation
          
          extension TimeInterval {
          
          var stringValue: String {
              guard self > 0 && self < Double.infinity else {
                  return "unknown"
              }
              let time = NSInteger(self)
          
              let ms = Int((self.truncatingRemainder(dividingBy: 1)) * 1000)
              let seconds = time % 60
              let minutes = (time / 60) % 60
              let hours = (time / 3600)
          
              return String(format: "%0.2d:%0.2d:%0.2d.%0.3d", hours, minutes, seconds, ms)
          
          }
          }
          

          【讨论】:

            【解决方案12】:

            您可以使用MeasurementUnitDurationTimeInterval 值转换为任何持续时间单位。要查看毫秒结果,您需要 UnitDuration.milliseconds,它需要 iOS 13.0、tvOS 13.0、watchOS 6.0 或 macOS 10.15。我把所有应该做的动作都放在func convertDurationUnitValueToOtherUnits(durationValue:durationUnit:smallestUnitDuration:)(Swift 5.1.3/Xcode 11.3.1)中:

            import Foundation
            
            @available(iOS 10.0, tvOS 10.0, watchOS 3.0, macOS 10.12, *)
            func convert<MeasurementType: BinaryInteger>(
                measurementValue: Double, unitDuration: UnitDuration, smallestUnitDuration: UnitDuration
            ) -> (MeasurementType, Double) {
                let measurementSmallest = Measurement(
                    value: measurementValue,
                    unit: smallestUnitDuration
                )
                let measurementSmallestValue = MeasurementType(measurementSmallest.converted(to: unitDuration).value)
                let measurementCurrentUnit = Measurement(
                    value: Double(measurementSmallestValue),
                    unit: unitDuration
                )
                let currentUnitCount = measurementCurrentUnit.converted(to: smallestUnitDuration).value
                return (measurementSmallestValue, measurementValue - currentUnitCount)
            }
            
            @available(iOS 10.0, tvOS 10.0, watchOS 3.0, macOS 10.12, *)
            func convertDurationUnitValueToOtherUnits<MeasurementType: BinaryInteger>(
                durationValue: Double,
                durationUnit: UnitDuration,
                smallestUnitDuration: UnitDuration
            ) -> [MeasurementType] {
                let basicDurationUnits: [UnitDuration] = [.hours, .minutes, .seconds]
                let additionalDurationUnits: [UnitDuration]
                if #available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *) {
                    additionalDurationUnits = [.milliseconds, .microseconds, .nanoseconds, .picoseconds]
                } else {
                    additionalDurationUnits = []
                }
                let allDurationUnits = basicDurationUnits + additionalDurationUnits
                return sequence(
                    first: (
                        convert(
                            measurementValue: Measurement(
                                value: durationValue,
                                unit: durationUnit
                            ).converted(to: smallestUnitDuration).value,
                            unitDuration: allDurationUnits[0],
                            smallestUnitDuration: smallestUnitDuration
                        ),
                        0
                    )
                ) {
                    if allDurationUnits[$0.1] == smallestUnitDuration || allDurationUnits.count <= $0.1 + 1 {
                        return nil
                    } else {
                        return (
                            convert(
                                measurementValue: $0.0.1,
                                unitDuration: allDurationUnits[$0.1 + 1],
                                smallestUnitDuration: smallestUnitDuration
                            ),
                            $0.1 + 1
                        )
                    }
                }.compactMap { $0.0.0 }
            }
            

            你可以这样称呼它:

            let intervalToConvert: TimeInterval = 12345.67
            let result: [Int] = convertDurationUnitValueToOtherUnits(
                durationValue: intervalToConvert,
                durationUnit: .seconds,
                smallestUnitDuration: .milliseconds
            )
            print("\(result[0]) hours, \(result[1]) minutes, \(result[2]) seconds, \(result[3]) milliseconds") // 3 hours, 25 minutes, 45 seconds, 670 milliseconds
            

            如您所见,我没有使用像 60 和 1000 这样的数字常量来获得结果。

            【讨论】:

              【解决方案13】:

              Swift 4 扩展 - 具有纳秒精度

              import Foundation
              
              extension TimeInterval {
              
                  func toReadableString() -> String {
              
                      // Nanoseconds
                      let ns = Int((self.truncatingRemainder(dividingBy: 1)) * 1000000000) % 1000
                      // Microseconds
                      let us = Int((self.truncatingRemainder(dividingBy: 1)) * 1000000) % 1000
                      // Milliseconds
                      let ms = Int((self.truncatingRemainder(dividingBy: 1)) * 1000)
                      // Seconds
                      let s = Int(self) % 60
                      // Minutes
                      let mn = (Int(self) / 60) % 60
                      // Hours
                      let hr = (Int(self) / 3600)
              
                      var readableStr = ""
                      if hr != 0 {
                          readableStr += String(format: "%0.2dhr ", hr)
                      }
                      if mn != 0 {
                          readableStr += String(format: "%0.2dmn ", mn)
                      }
                      if s != 0 {
                          readableStr += String(format: "%0.2ds ", s)
                      }
                      if ms != 0 {
                          readableStr += String(format: "%0.3dms ", ms)
                      }
                      if us != 0 {
                          readableStr += String(format: "%0.3dus ", us)
                      }
                      if ns != 0 {
                          readableStr += String(format: "%0.3dns", ns)
                      }
              
                      return readableStr
                  }
              }
              

              【讨论】:

                【解决方案14】:

                转换成swift 2扩展+可变格式:

                extension NSTimeInterval {
                
                    func timeIntervalAsString(format format : String = "hh:mm:ss:sss") -> String {
                        let ms      = Int((self % 1) * 1000)
                        let asInt   = NSInteger(self)
                        let s = asInt % 60
                        let m = (asInt / 60) % 60
                        let h = (asInt / 3600)
                
                        var value = format
                        value = value.replace("hh",  replacement: String(format: "%0.2d", h))
                        value = value.replace("mm",  replacement: String(format: "%0.2d", m))
                        value = value.replace("sss", replacement: String(format: "%0.3d", ms))
                        value = value.replace("ss",  replacement: String(format: "%0.2d", s))
                        return value
                    }
                
                }
                
                extension String {
                    /**
                     Replaces all occurances from string with replacement
                     */
                    public func replace(string:String, replacement:String) -> String {
                        return self.stringByReplacingOccurrencesOfString(string, withString: replacement, options: NSStringCompareOptions.LiteralSearch, range: nil)
                    }
                
                }
                

                【讨论】:

                  【解决方案15】:

                  这里是@maslovsa 的略微改进版本,带有Precision 输入参数:

                  import Foundation
                  
                  extension TimeInterval {
                  
                      enum Precision {
                          case hours, minutes, seconds, milliseconds
                      }
                  
                      func toString(precision: Precision) -> String? {
                          guard self > 0 && self < Double.infinity else {
                              assertionFailure("wrong value")
                              return nil
                          }
                  
                          let time = NSInteger(self)
                  
                          let ms = Int((self.truncatingRemainder(dividingBy: 1)) * 1000)
                          let seconds = time % 60
                          let minutes = (time / 60) % 60
                          let hours = (time / 3600)
                  
                          switch precision {
                          case .hours:
                              return String(format: "%0.2d", hours)
                          case .minutes:
                              return String(format: "%0.2d:%0.2d", hours, minutes)
                          case .seconds:
                              return String(format: "%0.2d:%0.2d:%0.2d", hours, minutes, seconds)
                          case .milliseconds:
                              return String(format: "%0.2d:%0.2d:%0.2d.%0.3d", hours, minutes, seconds, ms)
                          }
                      }
                  }
                  
                  

                  及用法:

                  let time: TimeInterval = (60 * 60 * 8) + 60 * 24.18
                  let hours = time.toString(precision: .hours) // 08
                  let minutes = time.toString(precision: .minutes) // 08:24
                  let seconds = time.toString(precision: .seconds) // 08:24:10
                  let milliseconds = time.toString(precision: .milliseconds) // 08:24:10.799
                  

                  【讨论】:

                    猜你喜欢
                    • 2013-01-12
                    • 2018-11-16
                    • 2012-09-27
                    • 1970-01-01
                    • 2012-06-08
                    • 1970-01-01
                    • 2016-06-29
                    • 2011-06-13
                    相关资源
                    最近更新 更多