Reputation: 12405
I have two NSDate which are initiated from UTC dates. Lets call them (A & B)
I know that the A represents a day in China and B represents a day in USA. (I know the time zones.) How can I calculate the difference in days between the two...?
I have been using the following method which is obviously incorrect.
class func daysDifferenceIn(firstDate: NSDate, firstTimeZone: String, secondDate: NSDate, secondTimeZone: String) -> Int {
objc_sync_enter(self)
let firstDateComponents = NSCalendar.CommonCalendar.componentsInTimeZone(NSTimeZone(name: firstTimeZone)!, fromDate: firstDate)
let secondDateComponents = NSCalendar.CommonCalendar.componentsInTimeZone(NSTimeZone(name: secondTimeZone)!, fromDate: secondDate)
NSCalendar.CommonCalendar.timeZone = NSTimeZone(name: firstTimeZone)!
let firstCalDate = NSCalendar.CommonCalendar.dateFromComponents(firstDateComponents)
NSCalendar.CommonCalendar.timeZone = NSTimeZone(name: secondTimeZone)!
let secondCalDate = NSCalendar.CommonCalendar.dateFromComponents(secondDateComponents)
objc_sync_exit(self)
return firstCalDate!.numberOfDaysUntilDateTime(secondCalDate!)
}
func numberOfDaysUntilDateTime(toDateTime: NSDate, inTimeZone timeZone: NSTimeZone? = nil) -> Int {
let calendar = NSCalendar.CommonCalendar
if let timeZone = timeZone {
calendar.timeZone = timeZone
}
var fromDate: NSDate?, toDate: NSDate?
calendar.rangeOfUnit(.Day, startDate: &fromDate, interval: nil, forDate: self)
calendar.rangeOfUnit(.Day, startDate: &toDate, interval: nil, forDate: toDateTime)
let difference = calendar.components(.Day, fromDate: fromDate!, toDate: toDate!, options: [])
return difference.day
}
I can manually subtract day components from firstDateComponents
and secondDateComponents
which I don't want to do as I have to look for edge cases of 31 and 28 and so on.
Any help is appreciated. Thanks.
UPDATE
First date is 2017-02-10 16:15:00 +0000 Second date is 2017-02-11 03:20:00 +0000 Both are UTC.
firstTimeZone String "Asia/Shanghai" secondTimeZone String "America/Los_Angeles"
So the day difference is -1 Day. Basically I am implementing flight status and you can see the following link as the flight lands 1 day prior to take day. As it flies from West to East.
https://www.google.co.in/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#q=ua+890
Also a description of Date components.
Printing description of firstDateComponents:
<NSDateComponents: 0x600000142310>
Calendar: <CFCalendar 0x60000088b6d0 [0x10c5d3df0]>{identifier = 'gregorian'}
TimeZone: Asia/Shanghai (GMT+8) offset 28800
Era: 1
Calendar Year: 2017
Month: 2
Leap month: no
Day: 11
Hour: 0
Minute: 15
Second: 0
Nanosecond: 0
Quarter: 0
Year for Week of Year: 2017
Week of Year: 6
Week of Month: 2
Weekday: 7
Weekday Ordinal: 2
Printing description of secondDateComponents:
<NSDateComponents: 0x60000014b8f0>
Calendar: <CFCalendar 0x60000049b620 [0x10c5d3df0]>{identifier = 'gregorian'}
TimeZone: America/Los_Angeles (PST) offset -28800
Era: 1
Calendar Year: 2017
Month: 2
Leap month: no
Day: 10
Hour: 19
Minute: 20
Second: 0
Nanosecond: 0
Quarter: 0
Year for Week of Year: 2017
Week of Year: 6
Week of Month: 2
Weekday: 6
Weekday Ordinal: 2
Upvotes: 0
Views: 854
Reputation: 131408
This is an odd case. You're looking for the difference in calendar dates between two Dates when those dates are evaluated in a specific time zone.
I did some playing, and came up with code that works for dates that fall in the same year:
let date = Date()
guard let nycTimeZone = TimeZone(abbreviation: "EST"),
let nzTimeZone = TimeZone(abbreviation: "NZDT") else {
fatalError()
}
var nycCalendar = Calendar(identifier: .gregorian)
nycCalendar.timeZone = nycTimeZone
var nzCalendar = Calendar(identifier: .gregorian)
nzCalendar.timeZone = nzTimeZone
let now = Date()
let nycDayOfYear = nycCalendar.ordinality(of: .day, in: .year, for: now)
var nzDayOfYear = nzCalendar.ordinality(of: .day, in: .year, for: now)
I'm using New York and Aukland, NZ as my time zones because as of the time of this writing, those zones are on different dates.
As of now (~12:00 PM on Feb 11, 2017 in US Eastern Standard Time (UTC - 5) the code above gives
nycDayOfYear = 42
and
nzDayOfYear = 43
It would take some work to make that calculation work across year boundaries.
Curiously, the following code:
var nzDayOfEra = nzCalendar.ordinality(of: .day, in: .era, for: now)
let nycDayOfEra = nycCalendar.ordinality(of: .day, in: .era, for: now)
Gives the same value for both NZ and NYC. I'm not sure why.
Ok, I did some experimenting and got code that works. What I do is to convert both dates to month/day/year date components using a calendar set to the local time zone for each time. Then I use a method dateComponents(_:from:to:)
to calculate the difference between those 2 DateComponents
, in days:
import UIKit
let date = Date()
guard let nycTimeZone = TimeZone(abbreviation: "EST"),
let nzTimeZone = TimeZone(abbreviation: "NZDT") else {
fatalError()
}
var nycCalendar = Calendar(identifier: .gregorian)
nycCalendar.timeZone = nycTimeZone
var nzCalendar = Calendar(identifier: .gregorian)
nzCalendar.timeZone = nzTimeZone
let now = Date()
let nycDateComponents = nycCalendar.dateComponents([.month, .day, .year], from: now)
let nzDateComponents = nzCalendar.dateComponents([.month, .day, .year], from: now)
let difference = Calendar.current.dateComponents([.day],
from: nycDateComponents,
to: nzDateComponents)
let daysDifference = difference.days
As of this writing that gives a daysDifference of 1. Since we're using the dateComponents(_:from:to:)
function, it takes care of the math to calculate the number of days difference between the 2 month/day/year DateComponents
.
Upvotes: 3
Reputation: 130092
A NSDate
represents a moment in time. It has no time zone. Only string representations of dates have time zone information.
If you have the dates, just take the number of days between them. Don't worry about time zones.
Usually:
let difference = calendar.components(.Day, fromDate: self, toDate: toDate!, options: [])
return difference.day
should be enough.
Upvotes: 1
Reputation: 829
Have you tried using let interval = laterDate.timeIntervalSinceDate(earlierDate)
? This will return the difference between the two dates in seconds.
Upvotes: 0