计算 Swift 中两个日期之间的差异
Calculating the difference between two dates in Swift
我见过很多方法如何根据特定日期组件计算两个日期之间的差异,例如以天、小时、月等为单位(参见 this answer on Whosebug):
Calendar.current.dateComponents([.hour], from: fromDate, to: toDate).hour
Calendar.current.dateComponents([.day], from: fromDate, to: toDate).day
Calendar.current.dateComponents([.month], from: fromDate, to: toDate).month
我没有看到的是如何用实际的 Date
对象进行计算。像
func computeNewDate(from fromDate: Date, to toDate: Date) -> Date
let delta = toDate - fromDate
let today = Date()
if delta < 0 {
return today
} else {
return today + delta
}
}
我已经看到 iOS 10 中引入的 DateInterval
类型,但根据文档
[it] does not support reverse intervals i.e. intervals where the duration is less than 0 and the end date occurs earlier in time than the start date.
这使得使用日期进行计算本来就很困难 – 特别是当您不知道哪个日期较早时。
是否有任何简洁明了的方法直接计算 Date
s 之间的时间差(并再次将它们添加到 Date
个实例)不用计算 timeIntervalSinceReferenceDate
?
怎么样……
func computeNewDate(from fromDate: Date, to toDate: Date) -> Date {
let delta = Calendar.current.dateComponents([.second], from: fromDate, to: toDate).second!
return Calendar.current.date(byAdding: .second, value: delta, to: Date())!
}
我最终为 Date
创建了一个自定义运算符:
extension Date {
static func - (lhs: Date, rhs: Date) -> TimeInterval {
return lhs.timeIntervalSinceReferenceDate - rhs.timeIntervalSinceReferenceDate
}
}
有了这个运算符,我现在可以在更抽象的层面上计算两个日期之间的差异,而不用关心 timeIntervalSinceReferenceDate
或参考日期到底是什么——而且不会丢失精度,例如:
let delta = toDate - fromDate
显然,我没有做太多改变,但对我来说它更具可读性和结果:Swift 已经为 Date
和 TimeInterval
:
/// Returns a `Date` with a specified amount of time added to it.
public static func + (lhs: Date, rhs: TimeInterval) -> Date
所以它已经支持
Date + TimeInterval = Date
所以应该也支持
Date - Date = TimeInterval
在我看来,这就是我在 -
运算符的简单实现中添加的内容。现在我可以完全按照我的问题中提到的那样简单地编写示例函数:
func computeNewDate(from fromDate: Date, to toDate: Date) -> Date
let delta = toDate - fromDate // `Date` - `Date` = `TimeInterval`
let today = Date()
if delta < 0 {
return today
} else {
return today + delta // `Date` + `TimeInterval` = `Date`
}
}
很可能这有一些我目前还没有意识到的缺点,我很想听听你对此的看法。
简直toDate.timeIntervalSince(fromDate)
.
要在不添加任何扩展的情况下重新实现您的函数:
func computeNewDate(from fromDate: Date, to toDate: Date) -> Date {
let delta = toDate.timeIntervalSince(fromDate)
let today = Date()
if delta < 0 {
return today
} else {
return today.addingTimeInterval(delta)
}
}
您可以使用自定义运算符进行扩展,return 元组
extension Date {
static func -(recent: Date, previous: Date) -> (month: Int?, day: Int?, hour: Int?, minute: Int?, second: Int?) {
let day = Calendar.current.dateComponents([.day], from: previous, to: recent).day
let month = Calendar.current.dateComponents([.month], from: previous, to: recent).month
let hour = Calendar.current.dateComponents([.hour], from: previous, to: recent).hour
let minute = Calendar.current.dateComponents([.minute], from: previous, to: recent).minute
let second = Calendar.current.dateComponents([.second], from: previous, to: recent).second
return (month: month, day: day, hour: hour, minute: minute, second: second)
}
}
使用:
let interval = Date() - updatedDate
print(interval.day)
print(interval.month)
print(interval.hour)
我找到了一个内置解决方案来计算两个日期之间的差异。
let delta = toDate.timeIntervalSince(fromDate)
您可以使用:
let delta = fromDate.distance(to: toDate)
我见过很多方法如何根据特定日期组件计算两个日期之间的差异,例如以天、小时、月等为单位(参见 this answer on Whosebug):
Calendar.current.dateComponents([.hour], from: fromDate, to: toDate).hour
Calendar.current.dateComponents([.day], from: fromDate, to: toDate).day
Calendar.current.dateComponents([.month], from: fromDate, to: toDate).month
我没有看到的是如何用实际的 Date
对象进行计算。像
func computeNewDate(from fromDate: Date, to toDate: Date) -> Date
let delta = toDate - fromDate
let today = Date()
if delta < 0 {
return today
} else {
return today + delta
}
}
我已经看到 iOS 10 中引入的 DateInterval
类型,但根据文档
[it] does not support reverse intervals i.e. intervals where the duration is less than 0 and the end date occurs earlier in time than the start date.
这使得使用日期进行计算本来就很困难 – 特别是当您不知道哪个日期较早时。
是否有任何简洁明了的方法直接计算 Date
s 之间的时间差(并再次将它们添加到 Date
个实例)不用计算 timeIntervalSinceReferenceDate
?
怎么样……
func computeNewDate(from fromDate: Date, to toDate: Date) -> Date {
let delta = Calendar.current.dateComponents([.second], from: fromDate, to: toDate).second!
return Calendar.current.date(byAdding: .second, value: delta, to: Date())!
}
我最终为 Date
创建了一个自定义运算符:
extension Date {
static func - (lhs: Date, rhs: Date) -> TimeInterval {
return lhs.timeIntervalSinceReferenceDate - rhs.timeIntervalSinceReferenceDate
}
}
有了这个运算符,我现在可以在更抽象的层面上计算两个日期之间的差异,而不用关心 timeIntervalSinceReferenceDate
或参考日期到底是什么——而且不会丢失精度,例如:
let delta = toDate - fromDate
显然,我没有做太多改变,但对我来说它更具可读性和结果:Swift 已经为 Date
和 TimeInterval
:
/// Returns a `Date` with a specified amount of time added to it. public static func + (lhs: Date, rhs: TimeInterval) -> Date
所以它已经支持
Date + TimeInterval = Date
所以应该也支持
Date - Date = TimeInterval
在我看来,这就是我在 -
运算符的简单实现中添加的内容。现在我可以完全按照我的问题中提到的那样简单地编写示例函数:
func computeNewDate(from fromDate: Date, to toDate: Date) -> Date
let delta = toDate - fromDate // `Date` - `Date` = `TimeInterval`
let today = Date()
if delta < 0 {
return today
} else {
return today + delta // `Date` + `TimeInterval` = `Date`
}
}
很可能这有一些我目前还没有意识到的缺点,我很想听听你对此的看法。
简直toDate.timeIntervalSince(fromDate)
.
要在不添加任何扩展的情况下重新实现您的函数:
func computeNewDate(from fromDate: Date, to toDate: Date) -> Date {
let delta = toDate.timeIntervalSince(fromDate)
let today = Date()
if delta < 0 {
return today
} else {
return today.addingTimeInterval(delta)
}
}
您可以使用自定义运算符进行扩展,return 元组
extension Date {
static func -(recent: Date, previous: Date) -> (month: Int?, day: Int?, hour: Int?, minute: Int?, second: Int?) {
let day = Calendar.current.dateComponents([.day], from: previous, to: recent).day
let month = Calendar.current.dateComponents([.month], from: previous, to: recent).month
let hour = Calendar.current.dateComponents([.hour], from: previous, to: recent).hour
let minute = Calendar.current.dateComponents([.minute], from: previous, to: recent).minute
let second = Calendar.current.dateComponents([.second], from: previous, to: recent).second
return (month: month, day: day, hour: hour, minute: minute, second: second)
}
}
使用:
let interval = Date() - updatedDate
print(interval.day)
print(interval.month)
print(interval.hour)
我找到了一个内置解决方案来计算两个日期之间的差异。
let delta = toDate.timeIntervalSince(fromDate)
您可以使用:
let delta = fromDate.distance(to: toDate)