Objective-C: Get the number of calendar days between two dates - objective-c

I just don't get the correct result...so depending on the timezone I want the calendar day difference between two dates. So if one starts at 23:00 on day 1 and ends on 14:00 on day 2 it should return 1. Now my method returns 0, why? Because it's less than 24 hours? Example:
MY Nslog:
CheckForPictures departure date: Tue Jan 28 23:10:00 2020 destinationDate: Wed Jan 29 09:30:00 2020 in timeZone:Europe/Zurich and get a day difference: 0
(Computer has also timezone Zurich, so it is local time)
My Method:
NSCalendar *calendar = [NSCalendar currentCalendar];
[calendar setTimeZone:timeZone];
NSDateComponents *components = [calendar components:NSCalendarUnitDay
fromDate:self.departureTime
toDate:self.destinationTime
options:0];
NSLog(#"CheckForPictures departure date: %# destinationDate: %# in timeZone:%# and get a day difference: %ld", self.departureTime, self.destinationTime, timeZone.name, components.day);
return components.day;
And this code returns 0 and logs above log...

I believe you're asking NSCalendar the wrong question. You want to know if the arrival date is different than the departure date, but you're asking for the number of days between arrival and departure. A date change could happen even if the difference in time is only a few minutes. "A few minutes" rounds to "0 days" if you ask how many days have passed.
You actually want to know if the date has changed. I think I would be doing something like getting the day of the month for each date and comparing that. Since no months have 1 day, I would think that would work.

With Craigs input I came up with this solution:
- (NSInteger)calendarDaysBetweenDepartureAndArrivalTimeForTimeZone:(NSTimeZone *)timeZone
{
NSCalendar *calendar = [NSCalendar currentCalendar];
[calendar setTimeZone:timeZone];
NSDateComponents *departureComponents = [calendar components:(NSCalendarUnitDay) fromDate:self.departureTime];
NSDateComponents *destinationComponents = [calendar components:(NSCalendarUnitDay) fromDate:self.destinationTime];
NSInteger difference = destinationComponents.day - departureComponents.day;
if(difference < 0){
//Month overlapping
NSRange range = [calendar rangeOfUnit:NSCalendarUnitDay inUnit:NSCalendarUnitMonth forDate:self.departureTime];
difference = range.length - departureComponents.day + departureComponents.day;
}
NSLog(#"CheckForPictures departure date: %# destinationDate: %# in timeZone:%# and get a day difference: %ld", self.departureTime, self.destinationTime, timeZone.name, difference);
return difference;
}

Related

Setting NSDateComponents results in incorrect NSDate

I'm trying to get an NSDate object that has 21:00 as the local time - don't care about what day. I'm scratching my head at this very strange result:
NSCalendar *calendar = [[NSCalendar alloc]initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *components = [[NSDateComponents alloc] init];
[components setHour:21];
[components setMinute:0];
[components setSecond:0];
NSDate *date = [calendar dateFromComponents:components];
NSLog(#"%#", date);
The result is 0001-01-02 04:52:58 +0000
I have no idea why. The current time is 17:34 PST, but the result doesn't change with the local time.
If I adjust the setMinute and setSecond lines to
[components setMinute:7];
[components setSecond:2];
I get 0001-01-02 05:00:00 +0000, which is correct (21:00 PST).
The problem is that railroad time wasn't implemented until November 18, 1883. You're neglecting to set a year so you're getting a date before that. Prior to the implementation of railroad time, the US time zones weren't exact hour differences from GMT. I'm not sure exactly what time zone Apple selects for you but whichever it was seems to have been adjusted by 7 minutes and 2 seconds upon the move to PST in 1883.

Converting NSDate

I have an NSDate (lets call it x), 12 September, 2012 10:18PM (GMT). I want to convert x to a minute before my current time zone's (EST) midnight. So, x represented in EST with NSDateFormatter after conversion would be 12 September, 2012 11:59PM (EST). What's the best way to do this?
Thanks
Take a look at NSDateComponents: https://developer.apple.com/library/ios/#documentation/Cocoa/Reference/Foundation/Classes/NSDateComponents_Class/Reference/Reference.html
I believe you'll need to convert the NSDate to NSDateComponents, set the time to 11:59PM, then convert back to NSDate.
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *components = [calendar components:(NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit) fromDate:date];
[components setHour:23];
[components setMinute:59];
NSDate *convertedDate = [calendar dateFromComponents:components];
NSLog(#"date=%#, convertedDate=%#", date, convertedDate);
Such manipulations can be easily done with the numeric representation of a date. In this representation, you deal with the number of seconds since a reference date.
The reference date for the purpose of the timeIntervalSinceReferenceDate is January 1st, 2001, at 00:00:00 GMT.
NSDate* date = [NSDate date];
NSInteger secondsSinceReferenceDate = [date timeIntervalSinceReferenceDate];
secondsSinceReferenceDate += 86400 - (secondsSinceReferenceDate % 86400);
secondsSinceReferenceDate -= 60;
secondsSinceReferenceDate -= [NSTimeZone.localTimeZone secondsFromGMTForDate:date];
NSDate* justBeforeToday =
[NSDate dateWithTimeIntervalSinceReferenceDate:secondsSinceReferenceDate];
NSLog(#"Date used was %#", date);
NSLog(#"Just before tomorrow is %#", justBeforeToday);
Since there are 86400 seconds in a day (24 hours times 60 minutes 60 times 60 seconds = 86400 seconds), you know that 86400 - (secondsSinceReferenceDate % 86400) is the number of seconds there are still to midnight. So if you take today's date (or any other valid date), add this number of seconds, and then subtract another 60 seconds, you'll have today's evening at 11:59 PM in the GMT timezone.
With [NSTimeZone.localTimeZone secondsFromGMTForDate:], you know how many seconds your timezone is offset from the GMT timezone. By subtracting this offset to your integer representation, you effectively get when it will be 11:59 PM in your local timezone.
Here's a sample output:
Date used was 2012-09-12 22:37:49 +0000
Just before tomorrow is 2012-09-13 03:59:00 +0000
I'm in the EDT timezone too, and this looks like the correct answer (remember Standard Time is -5 from GMT, but right now we're in daylight savings, so it's -4 from GMT, which is invariant).

iOS - Getting wrong number of days for NSDate/NSCalendar difference

I'm trying to get the difference of days between today [NSDate date] and a day that the user selects from a UIDatePicker, d, which will be returned as an integer.
Here's what I'm using to figure out the difference:
NSDate *startDate = d;
NSDate *endDate = [NSDate date];
NSLog(#"startDate: %#",startDate);
NSLog(#"endDate: %#",endDate);
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
[gregorian setTimeZone:[NSTimeZone timeZoneWithName:#"GMT"]];
NSDateComponents *components = [gregorian components:NSDayCalendarUnit
fromDate:endDate
toDate:startDate
options:0];
NSInteger days = [components day];
NSLog(#"Days: %i",days);
Both startDate and endDate are returned correctly, but the problem I get is the day difference I get is wrong. For example, when I select today's date, the difference is 0, when I select tomorrow, the difference is still 0, and when I select the day after, the difference is only 1, when it should be 2.
Does anyone have any ideas on what I could do to fix this? It's driving me crazy and I don't know what the deal is with it.
For example, when I select today's date, the difference is 0, when I select tomorrow, the difference is still 0, and when I select the day
after, the difference is only 1, when it should be 2.
assume tomorrows selected date is 05:00 pm and todays current date is 08:00 PM. Then if try to get the difference between the dates based on the number of day then it should be zero. Because the difference between the above mention dates is 2 hour less then one complete day.
I hope this will solve your problem. Always set the component of both the dates which you are comparing to same. Use NSDateComponent for this purpose.
Usually with this type of issue, it has to do with different date formats which causes this exact problem.
Check this question as reference: find total number of days between two dates in iphone
OR
Objective C - calculating the number of days between two dates

NSDateComponents issue - incorrect day

I have a NSDateComponents problem. I have two NSDates that I am trying to compare by checking if their year, month and day match. This I am doing by converting the NSDate values to these integer components as follows:
//NSDate *cgiDate is previously set to 2011-08-04 00:00:00 +0000
//NSDate *orderDate is previously set to 2011-08-04 14:49:02 +0000
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *cgiDateComponents = [calendar components:( NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit ) fromDate:cgiDate];
NSCalendar *orderCalendar = [NSCalendar currentCalendar];
NSDateComponents *orderDateComponents = [orderCalendar components:( NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit ) fromDate:orderDate];
if (([cgiDateComponents day] == [orderDateComponents day]) &&
([cgiDateComponents month] == [orderDateComponents month]) &&
([cgiDateComponents year] == [orderDateComponents year])) {
GHTestLog(#"MATCHED");
} else {
GHTestLog(#"Not matched");
GHTestLog(#"Day: %d vs. %d", [cgiDateComponents day], [orderDateComponents day]);
}
My result is Not Matched, Day: 3 vs. 4. Why would this be?
I have read with great interest the following questions:
NSDateComponents - day method returning wrong day and
https://stackoverflow.com/questions/3920445/nsdatecomponents-incorrectly-reporting-day however neither answer my question of why this is not working.
Any advice?
I think the issue is the following:
Your dates are set in GMT time zone (+0000)
If you are in the US, for example at GTM-6, then by the -currentCalendar the first date will be 6pm on Aug 3rd while second date will be 8:49am on Aug 4th.
You should force your calendar to have the UTC (GMT) timezone, or put the dates in your time zone, depending what is correct for your application.
It looks like you have a time zone issue. Though your dates are set at time zone +0000, your [NSCalendar calendar] call likely returns you a calendar for your local time zone. Given the adjustment to local time, the orderDate is likely in the next day. Manually set your calendars to time zone +0000.
NSDate has an isEqualToDate: function. so what you are trying to do can be done by:
[datea isEqualToDate:dateb];
there is also a Compare: function available, that returns the ordering of the dates.
edit: I'm now aware this doesn't answer your question about why the days return different values when they are set the same. Sorry! this still may help make your code a bit cleaner.

NSDateComponents returns week 53 on 1/1/1970

So when extracting the dates components from NSDate object using NSCalendar and NSDateComponents I encountered a weird behavior.
If the date is 0 sec from 1970 the week component will return 53.
Is there an explination for this or a way to fix other than the obvious way of modulus 52?
here is the code you can run on your machine to test:
-
(void)testDate {
NSCalendar *cal = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDate *date = [NSDate dateWithTimeIntervalSince1970:0];
NSDateComponents *comp = [cal components:(NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit | NSWeekCalendarUnit) fromDate:date];
DLog(#"%d/%d/%d week: %d", [comp day],[comp month], [comp year], [comp week]);
}
and here is the output:
31/12/1969 week: 53
(gdb) po date
1970-01-01 00:00:00 +0000
(gdb)
Well I got this,
2011-06-22 22:38:50.516 SmallTasks[23164:903] 1/1/1970 week: 1
So I am bit surprised by the result you got but I am not that surprised that a week: 53 turned up as 52 * 7 = 364 and we've 365 days in a year. For that to happen I would expect the week to start on Sunday on 1969 but it didn't.
You my friend have discovered the leap week. I have run across this doing some SQL reporting a couple years back.