我正在计算两个日期之间的时差。我有一段代码:
func timeAgoSinceDate(_ date:Date, numericDates:Bool) -> String {
let calendar = Calendar.current
let now = Date()
let components:DateComponents = (calendar as NSCalendar).components([NSCalendar.Unit.minute , NSCalendar.Unit.hour , NSCalendar.Unit.day , NSCalendar.Unit.weekOfYear , NSCalendar.Unit.month , NSCalendar.Unit.year , NSCalendar.Unit.second], from: now, to: date, options: NSCalendar.Options())
print(now)
print(date)
print(components.month)
这些是我在控制台中看到的一些例子:
2016-10-29 16:12:34 +0000
2017-03-29 16:03:13 +0000
Optional(4) //I think it should return 5?
2016-10-29 16:12:34 +0000
2017-01-29 17:03:13 +0000
Optional(2) //again, why 2 instead of 3?
2016-10-29 16:12:34 +0000
2015-09-30 15:54:20 +0000
Optional(0) //why 0 since it's almost whole year?
2016-10-29 16:12:34 +0000
2016-05-29 14:09:31 +0000
Optional(-5) //this seems to be fine
依此类推......这里有什么问题?
我遇到的问题是日期计算。在我的代码中我正在做:
if (components.month! >= 2) {
return "in \(components.month!) months"
} else if (components.month! >= 1){
if (numericDates){
return "in 1 month"
} else {
return "in one month"
}
}
else if (components.month! <= -2) {
return "\(components.month!) months ago"
} else if (components.month! <= -1){
if (numericDates){
return "1 month ago"
} else {
return "one month ago"
}
}
然后,由于进行了我的计算,目前当一个日期为2016-10-29 16:32:54 +0000
而另一个日期为2017-01-29 17:03:13 +0000
时,用户会看到in 2 months
。这是因为整个print(components)
返回:
year: 0 month: 2 day: 2 hour: 23 minute: 30 second: 18 weekOfYear: 4 isLeapMonth: false
但在现实生活中它应该返回3,因为这是10月和1月之间的差异。有没有比一堆if
语句更好地计算这种差异的方法?
答案 0 :(得分:3)
2016-10-29 16:12:34 +0000
2017-03-29 16:03:13 +0000
Optional(4) //I think it should return 5?
自16:03起&lt; 16:12,你需要再增加9分21秒才能返回5
2016-10-29 16:12:34 +0000
2017-01-29 17:03:13 +0000
Optional(2) //again, why 2 instead of 3?
夏令时是2016年11月6日。您将失去一小时。我很确定这就是为什么它认为只有2个月的时间。
添加一小时:
2016-10-29 16:12:34 +0000
2017-01-29 18:03:13 +0000
Optional(3)
你得到&#39; 3&#39;
更改月份但保留原始小时数:
2016-7-29 16:12:34 +0000
2016-10-29 17:03:13 +0000
Optional(3)
你也得到了&#39; 3&#39;
2016-10-29 16:12:34 +0000
2015-09-30 15:54:20 +0000
Optional(0) //why 0 since it's almost whole year?
日期组件返回组件定义中包含的最高单位的差异。在您的情况下,您已包含NSCalendar.Unit.year
。因此components.month
将返回月份单位,而不是月份的总差异。所以这个计算中的月份单位是0个月。如果你要将25年零5个月添加到某个日期,它将返回&#39; 5&#39;。但是,如果您要删除NSCalendar.Unit.year
,那么它将使用月份作为最高单位并返回&#39; 305&#39;
你可以像这样测试一些日期:
let startString = "2016-7-30 16:12:34 +0000"
let endString = "2016-10-30 17:03:13 +0000"
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z"
let now = formatter.date(from: startString)!
let date = formatter.date(from: endString)!
答案 1 :(得分:0)
从2016-10-29 16:12:34到2017-03-29 16:03:13还有4个月,28天,23个小时,50分钟和39秒
这就是为什么components.month
在第一个示例中评估为4
的原因。
如果您打算计算2016年10月之后的差异(月份) 到2017年3月,你必须计算之间的差异 两个日期的月份开始:
let startOfFirstMonth = calendar.date(from: calendar.dateComponents([.year, .month], from: firstDate))!
let startOfSecondMonth = calendar.date(from: calendar.dateComponents([.year, .month], from: secondDate))!
let comps = calendar.dateComponents([.month], from: startOfFirstMonth, to: startOfSecondMonth)
print(comps.month)
答案 2 :(得分:0)
这个答案旨在成为Frankie答案的补充信息。
func calendarTest(_ from: String, _ to: String) {
var calendar = Calendar.current
calendar.timeZone = TimeZone(identifier: "Europe/Paris")! //<- GMT+1
let inFormatter = DateFormatter()
inFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
inFormatter.timeZone = TimeZone(abbreviation: "UTC")!
guard
let now = inFormatter.date(from: from),
let date = inFormatter.date(from: to)
else {return}
//Removing "weeks" for clarity
let components = (calendar as NSCalendar).components([.minute, .hour, .day/*, .weekOfYear*/, .month, .year, .second], from: now, to: date, options: [])
let outFormatter = DateFormatter()
outFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
outFormatter.timeZone = calendar.timeZone
print("UTC time Localtime")
print(now, outFormatter.string(from: now))
print(date, outFormatter.string(from: date))
print(components)
}
使用上面的代码:
calendarTest("2016-10-29 16:12:34","2017-03-29 16:03:13")
calendarTest("2016-10-29 16:12:34","2017-03-29 16:12:34")
输出:
UTC time Localtime
2016-10-29 16:12:34 +0000 2016-10-29 18:12:34
2017-03-29 16:03:13 +0000 2017-03-29 18:03:13
year: 0 month: 4 day: 28 hour: 23 minute: 50 second: 39 isLeapMonth: false
UTC time Localtime
2016-10-29 16:12:34 +0000 2016-10-29 18:12:34
2017-03-29 16:12:34 +0000 2017-03-29 18:12:34
year: 0 month: 5 day: 0 hour: 0 minute: 0 second: 0 isLeapMonth: false
calendarTest("2016-10-29 16:12:34","2017-01-29 17:03:13")
calendarTest("2016-10-29 16:12:34","2017-01-29 17:12:34")
输出:
UTC time Localtime
2016-10-29 16:12:34 +0000 2016-10-29 18:12:34
2017-01-29 17:03:13 +0000 2017-01-29 18:03:13
year: 0 month: 2 day: 30 hour: 23 minute: 50 second: 39 isLeapMonth: false
UTC time Localtime
2016-10-29 16:12:34 +0000 2016-10-29 18:12:34
2017-01-29 17:12:34 +0000 2017-01-29 18:12:34
year: 0 month: 3 day: 0 hour: 0 minute: 0 second: 0 isLeapMonth: false
calendarTest("2016-10-29 16:12:34","2015-09-30 15:54:20")
输出:
UTC time Localtime
2016-10-29 16:12:34 +0000 2016-10-29 18:12:34
2015-09-30 15:54:20 +0000 2015-09-30 17:54:20
year: -1 month: 0 day: -29 hour: 0 minute: -18 second: -14 isLeapMonth: false
calendarTest("2016-10-29 16:12:34","2016-05-29 14:09:31")
输出:
UTC time Localtime
2016-10-29 16:12:34 +0000 2016-10-29 18:12:34
2016-05-29 14:09:31 +0000 2016-05-29 16:09:31
year: 0 month: -5 day: 0 hour: -2 minute: -3 second: -3 isLeapMonth: false
请记住Calendar.current
使用日期计算月数&amp; 次当地时区。
顺便说一句,在两个NSCalendar
之间获取DateComponents
时,您无需使用Date
。
let components = calendar.dateComponents([.minute, .hour, .day/*, .weekOfYear*/,.month, .year, .second], from: now, to: date)