Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios Swift中的DateComponents返回奇怪的值。为什么?_Ios_Swift_Nsdate_Nsdatecomponents - Fatal编程技术网

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:你说得对,那太简短了,我现在已经解决了,谢谢你的反馈然而,建议的解决方案应该适用于问题的所有情况(我从更新中了解到)。