2016-10-29 5 views
0

두 날짜 간의 시간 차이를 계산 중입니다. 나는 코드 조각이 :Swift의 DateComponents가 이상한 값을 반환합니다. 왜?

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 

등등 ... 무슨 문제가?

문제점은 날짜 계산과 관련되어 있습니다. 내 코드에서 내가 뭘 하나 날짜가 2016-10-29 16:32:54 +0000이고, 다른 하나는 2017-01-29 17:03:13 +0000 때 때문에 내 계산을 수행의 다음

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" 
     } 
    } 

을하고, 현재 사용자는 in 2 months을 본다. 그 때문에 전체 print(components) 반환 :

year: 0 month: 2 day: 2 hour: 23 minute: 30 second: 18 weekOfYear: 4 isLeapMonth: false 

하지만 10 월 월 사이의 차이이기 때문에 실생활에 3을 반환해야합니다. 이 차이를 계산하는 더 좋은 방법은 if 문장을 모두 내리는 것보다 낫지 않습니까? 이 5

2016-10-29 16:12:34 +0000 
2017-01-29 17:03:13 +0000 
Optional(2) //again, why 2 instead of 3? 

일광 절약 시간을 반환하기 전에 16시 3분 이후

+0

현재 시간대는 무엇입니까? 날짜는 UTC/GMT로 인쇄되지만 달력 계산은 로컬 달력/시간대에서 수행됩니다. * –

+1

첫 번째 예제에서는 지정된 날짜 사이에 * 5 개월 미만이므로 결과 4가 정확합니다. –

+0

hm하지만 시간대가'months'의 경우 계산에 영향을 미치지 않아야한다고 생각했습니다 ... 어쨌든'GMT + 1'에 있는데, 시간대와 독립적으로 계산을 수행 할 수있는 방법이 있습니까? – user3766930

답변

3
2016-10-29 16:12:34 +0000 
2017-03-29 16:03:13 +0000 
Optional(4) //I think it should return 5? 

이 < 16시 12분, 당신이 9 분 이상 21 초 추가해야하는 것은, 당신은 잃을 2016 년 11 월 6 일입니다 한시간. 나는 이것이 단지 2 개월의 시간이라고 생각하는 이유라고 확신한다. 원래 시간을 달 '3'

변경을

2016-10-29 16:12:34 +0000 
2017-01-29 18:03:13 +0000 
Optional(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? 

날짜 구성 요소 retur n 구성 요소 정의에 포함시킨 가장 높은 단위의 차이. 귀하의 경우에는 NSCalendar.Unit.year을 포함 시켰습니다. 따라서 components.month은 달 차이를 나타내는 것이 아니라 월 단위를 반환합니다. 따라서이 계산의 월 단위는 0 개월입니다. 날짜에 25 년 5 개월을 더하면 '5'를 반환합니다.

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)! 
0

있다 사개월 28 일 23시간 : 당신이 다음 NSCalendar.Unit.year을 제거했다 그러나 경우에 가장 높은 단위와 리턴 '305'

당신은이 같은 일부 날짜를 테스트 할 수 개월을 사용합니다 , 50 분 39 초부터 2016-10-29 16:12:34까지 2017-03-29 16:03:13 그 은 이 첫 번째 예에서 4으로 평가되는 이유입니다.

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) 
+1

나는 HH : mm : ss를 사용하지 않고 "2016-10-29에서 2017-03-29까지"를 평가하면 실제로 5 개월로 평가되기 때문에 첫 번째 진술에 동의하지 않습니다. 그러나 OP의 예에는 정확한 시간이 포함되어있어 5 개월 만 부끄러워하게 만듭니다. (내 아래로 투표하지 btw) – Frankie

+0

@ 프랜키 : 당신 말이 맞아, 그게 너무 많이 축약되었다, 나는 지금 고쳐 주셔서 감사합니다, 피드백을 위해! - 그러나 제안 된 솔루션은 질문의 모든 경우에 작동해야합니다 (업데이트로 이해함). –

0

: 당신의 의도 월 2017 2016년 10월 에서 (달)의 차이를 계산하는 경우

다음 달 두 날짜의의 시작 사이의 차이를 계산해야 이 답변은 Frankie의 대답에 대한 추가 정보입니다.

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 
상기 코드

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) 
} 

617,451,515,


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 날짜로 달을 계산 기억 0 번 로컬 시간대의입니다. 그런데


, 당신은 두 Date의 사이에 DateComponents을 가져올 때 NSCalendar를 사용할 필요가 없습니다.

let components = calendar.dateComponents([.minute, .hour, .day/*, .weekOfYear*/,.month, .year, .second], from: now, to: date)