Ios Swift中的DateComponents返回奇怪的值。为什么?
我在计算两次约会的时差。我有一段代码:Ios Swift中的DateComponents返回奇怪的值。为什么?,ios,swift,nsdate,nsdatecomponents,Ios,Swift,Nsdate,Nsdatecomponents,我在计算两次约会的时差。我有一段代码: func timeAgoSinceDate(_ date:Date, numericDates:Bool) -> String { let calendar = Calendar.current let now = Date() let components:DateComponents = (calendar as NSCalendar).components([NSCalendar.Unit.minute , NSCale
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"
}
}
但在现实生活中,它应该返回3,因为它是10月和1月之间的差值。有没有更好的方法来计算这种差异,而不是用一堆将所有内容取整的if
语句
2016-10-29 16:12:34 +0000
2017-03-29 16:03:13 +0000
Optional(4) //I think it should return 5?
由于16:03小于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日。你损失了一个小时。我很确定这就是为什么它认为只有两个月的时间
加上一小时:
2016-10-29 16:12:34 +0000
2017-01-29 18:03:13 +0000
Optional(3)
你得到'3'
更改月份,但保留原来的小时数:
2016-7-29 16:12:34 +0000
2016-10-29 17:03:13 +0000
Optional(3)
你也会得到“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?
日期组件返回组件定义中包含的最高单位的差值。在您的例子中,您已经包括了NSCalendar.Unit.year
。因此,components.month
将返回月份单位,而不是月份的总差值。因此,此计算中的月份单位为0个月。如果在一个日期上加上25年零5个月,它将返回“5”。但是,如果要删除NSCalendar.Unit.year
,则它将使用月作为最高单位,并返回“305”
您可以像这样测试某些日期:
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)!
从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)
此答案旨在作为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)
}
输出:
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
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
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
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
输出:
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
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
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
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
输出:
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
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
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
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
输出:
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
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
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
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
请记住日历。当前使用本地时区的日期和时间计算月份
顺便说一下,在获取两个日期之间的日期组件时,无需使用NSCalendar
let components = calendar.dateComponents([.minute, .hour, .day/*, .weekOfYear*/,.month, .year, .second], from: now, to: date)
你在哪个时区?日期以UTC/GMT格式打印,但日历计算是在本地日历/时区中完成的。在第一个示例中,给定日期之间的间隔不到5个月,因此结果4是正确的。嗯,但我认为时区不应影响月
情况下的计算。。。不管怎样,我在GMT+1
,有没有办法独立于时区进行计算?你可以将日历时区设置为GMT,但即使这样,在第一个示例中,你也会得到4而不是5,在第三个示例中,会得到0,因为相差不到一年。尝试打印(组件)
以查看实际差异。几乎在编程方面不是;-)我不同意第一种说法,因为如果你评估“从2016-10-29到2017-03-29”,而不使用HH:mm:ss,那么它实际上评估为5个月。但是OP的例子包括了精确的时间,这使得它只差5个月。(顺便说一句,这不是我的反对票)@Frankie:你说得对,那太简短了,我现在已经解决了,谢谢你的反馈然而,建议的解决方案应该适用于问题的所有情况(我从更新中了解到)。