Swift - 计算运行时间太长?
Swift - Calculating elapsed time takes too long?
我的服务器调用为我提供了 JSON 数据以及每条数据的日期时间,我想计算从现在到现在经过的时间并将其加载到我的数据结构中。我现在这样做的方式需要很长时间,我应该使用不同的设计实践吗? follow功能是我现在用的
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 对象的开销有点大。如果拥有 dateDiff
的对象在每次应用启动或 JSON 加载时创建一次,您可以优化的一件事是让您的日期格式化程序成为 class 的成员,这样您就不需要每次调用 dateDiff
.
时都重新创建它
换句话说,输入:
var formatter : DateFormatter
var dateFormatter : DateFormatter
在 class 的顶部,然后在 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"
}
但更好的方法是使用 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
出于性能原因,您应该将日期格式化程序的实例化从该方法中移除,因为这是众所周知的计算密集型。
我还建议使用 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)。如果您可以控制它,那可能是最佳实践,可以避免用户更改时区时出现问题;
我的服务器调用为我提供了 JSON 数据以及每条数据的日期时间,我想计算从现在到现在经过的时间并将其加载到我的数据结构中。我现在这样做的方式需要很长时间,我应该使用不同的设计实践吗? follow功能是我现在用的
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 对象的开销有点大。如果拥有 dateDiff
的对象在每次应用启动或 JSON 加载时创建一次,您可以优化的一件事是让您的日期格式化程序成为 class 的成员,这样您就不需要每次调用 dateDiff
.
换句话说,输入:
var formatter : DateFormatter
var dateFormatter : DateFormatter
在 class 的顶部,然后在 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"
}
但更好的方法是使用 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
出于性能原因,您应该将日期格式化程序的实例化从该方法中移除,因为这是众所周知的计算密集型。
我还建议使用 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)。如果您可以控制它,那可能是最佳实践,可以避免用户更改时区时出现问题;