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

Swift-计算经过的时间太长?,swift,datetime,nsdate,elapsedtime,Swift,Datetime,Nsdate,Elapsedtime,我的服务器调用为我提供了JSON数据,其中包含每个数据段的日期时间,我希望计算从现在到那时所经过的时间,并将其加载到我的数据结构中。我现在这样做需要很长时间,有没有其他的设计实践我应该使用?下面的函数就是我现在正在使用的 func dateDiff(_ dateStr:String) -> String { var timeAgo = "10m" let formatter = DateFormatter() formatter.dateFormat = "yyy

我的服务器调用为我提供了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
}

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

换言之,把:

var formatter : DateFormatter
var dateFormatter : DateFormatter 

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

您的代码太过冗长,一开始您可能会大幅缩短它:

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

但更好的方法是使用从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

出于性能方面的原因,您应该将日期格式化程序的实例化从方法中拉出来,因为这是出了名的计算密集型

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

因此,请定义两个格式化程序:

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())
}
还请注意:

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

另一件看起来可疑的事情是对时区使用
AST
。通常,日期字符串以GMT/UTC/Zulu格式保存(例如,RFC 3339或ISO 8601)。如果你能控制这一点,这可能是最好的做法,避免用户改变时区时出现问题

formatter
dateFormatter
之间的区别在哪里?后者似乎没有使用。为什么要将
Date()
转换为字符串并返回到
Date