Swift - 计算经过的时间需要太长时间?

Posted

技术标签:

【中文标题】Swift - 计算经过的时间需要太长时间?【英文标题】:Swift - Calculating elapsed time takes too long? 【发布时间】:2018-01-28 09:27:17 【问题描述】:

我的服务器调用为我提供了 JSON 数据,其中包含每条数据的日期时间,我想计算从现在到那时经过的时间并将其加载到我的数据结构中。我现在这样做的方式需要很长时间,我应该使用不同的设计实践吗?以下是我现在正在使用的功能

func dateDiff(_ dateStr:String) -> String 
    var timeAgo = "10m"

    let formatter = DateFormatter()
    formatter.dateFormat = "yyyy-MM-dd' 'HH:mm:ss"
    formatter.timeZone = NSTimeZone(name: "AST") as! TimeZone


    let dateFormatter = DateFormatter()
    dateFormatter.dateFormat = "yyyy-MM-dd' 'HH:mm:ss"
    dateFormatter.timeZone = NSTimeZone(name: "AST") as! TimeZone

    let now = formatter.string(from: Date())

    if let date = formatter.date(from: dateStr)
        if let nowDate = formatter.date(from: now)
        let components = Calendar.current.dateComponents([.day,.hour,.minute,.second], from: date, to: nowDate)
        let sec = components.second
        let min = components.minute
        let hours = components.hour
        let days = components.day
        if (sec! > 0)
            if let secc = sec 
                timeAgo = "\(secc)s"
            
        
        if (min! > 0)
            if let minn = min 
                timeAgo = "\(minn)m"
                        
        if(hours! > 0)
            if let hourss = hours 
                timeAgo = "\(hourss)h"
            
        
        if(days! > 0)
            if let dayss = days 
                timeAgo = "\(dayss)d"
            
        
    
  
    return timeAgo

【问题讨论】:

formatterdateFormatter 的区别在哪里?后者似乎未使用。为什么要将Date() 转换为字符串然后再转换回Date 看看DateComponentsFormatter 【参考方案1】:

你的代码太冗长了,你可以大大缩短它:

if let day = components.day, day > 0 
    timeAgo = "\(day)d"
 else if let hour = components.hour, hour > 0 
    timeAgo = "\(hour)h"
 else if let minute = components.minute, minute > 0 
    timeAgo = "\(minute)m"
 else if let second = components.second, second > 0 
    timeAgo = "\(second)s"


但更好的方法是使用 DateComponentsFormatter,自 ios 8 和 OS X 10.10 起可用:

let componentsFormatter = DateComponentsFormatter()
componentsFormatter.allowedUnits = [.second, .minute, .hour, .day]
componentsFormatter.maximumUnitCount = 1
componentsFormatter.unitsStyle = .abbreviated

let timeAgo = componentsFormatter.string(from: dateComponents)!

以下是它为您所做的一些示例:

let dateComponents1 = DateComponents(calendar: .current, day: 1, hour: 4, minute: 6, second: 3)
let dateComponents2 = DateComponents(calendar: .current, day: 0, hour: 4, minute: 6, second: 3)
let dateComponents3 = DateComponents(calendar: .current, day: 0, hour: 0, minute: 6, second: 3)
let dateComponents4 = DateComponents(calendar: .current, day: 0, hour: 0, minute: 0, second: 3)

print(componentsFormatter.string(from: dateComponents1)!) // 1d
print(componentsFormatter.string(from: dateComponents2)!) // 4h
print(componentsFormatter.string(from: dateComponents3)!) // 6m
print(componentsFormatter.string(from: dateComponents4)!) // 3s

【讨论】:

【参考方案2】:

出于性能原因,您应该从方法中提取日期格式化程序的实例化,因为这是众所周知的计算密集型。

我还建议使用DateComponentsFormatter 来简化经过时间的格式。

所以,定义你的两个格式化程序:

let dateFormatter: DateFormatter = 
    let _formatter = DateFormatter()
    _formatter.dateFormat = "yyyy-MM-dd' 'HH:mm:ss"
    _formatter.locale = Locale(identifier: "en_US_POSIX")
    _formatter.timeZone = TimeZone(abbreviation: "AST")  // Curious; we usually use `TimeZone(secondsFromGMT: 0)` (i.e. GMT/UTC/Zulu)
    return _formatter
()

let componentsFormatter: DateComponentsFormatter = 
    let _formatter = DateComponentsFormatter()
    _formatter.maximumUnitCount = 1
    _formatter.unitsStyle = .abbreviated
    return _formatter
()

然后你的功能就大大简化了:

func dateDiff(_ string: String) -> String? 
    guard let date = dateFormatter.date(from: string) else  return nil 

    return componentsFormatter.string(from: date, to: Date())

还要注意:

我直接使用TimeZone,而不是通过NSTimeZone往返; 我将locale 设置为en_US_POSIX,如果日期字符串的来源是Web 服务或数据库,您应该always use; 我消除了将“now”转换为字符串并返回的过程;直接使用Date()

唯一看起来可疑的另一件事是使用AST 作为时区。通常日期字符串保存在 GMT/UTC/Zulu 中(例如,RFC 3339 或 ISO 8601)。如果您对此有控制权,那可能是最佳做法,避免用户更改时区时出现问题;

【讨论】:

【参考方案3】:

每次调用dateDiff 时创建然后DateFormatter 对象有点昂贵。如果拥有 dateDiff 的对象在每次应用启动或 JSON 加载时创建一次,您可以优化的一件事是让您的日期格式化程序成为该类的成员,这样您就不会在每次调用 @ 时都重新创建它987654323@.

换句话说,把:

var formatter : DateFormatter
var dateFormatter : DateFormatter 

在类的顶部,然后在 init 函数中对其进行初始化。

【讨论】:

以上是关于Swift - 计算经过的时间需要太长时间?的主要内容,如果未能解决你的问题,请参考以下文章

减少功能有效,但需要太长时间,vue

计算矩阵的 Matthew 相关系数需要很长时间

用 std::chrono 计算持续时间在需要很长时间时给出 0 纳秒

简单的 MySQL 查询需要很长时间来计算

wcf 宁静服务中的长时间计算

php中的长时间计算导致503错误