Wrong Days Between Dates for Month of March - objective-c

I have a very interesting problem: When calculating the number of days between two dates, my calculator gives the wrong results for the month of March only. I have two text fields, one for each date. If I enter 3/7/12 in date1, and 3/13/12 in date2, the result is 7, which is correct (I am counting the first day as well). But when I enter date1 = 3/7/12 and date2 = 3/14/12, the result is still 7, but it should be 8. Likewise, if I enter date1 = 3/7/12 and date2 = 3/23/12, the result should be 17, but it is 16. If I change the month to April so that date1 = 4/7/12 and date2 = 4/23/12, the result is 17. Every month is working as intended, only the month of March is giving me wrong results. Does anyone have any idea what I am missing? Is this a timezone problem? How do I fix it? Here is my code:
NSDateFormatter *dateFormatter1 = [[NSDateFormatter alloc] init];
[dateFormatter1 setDateFormat:#"MM/dd/yyyy"];
NSDate *startdate1 = [dateFormatter1 dateFromString: date1.text];
NSDateFormatter *dateFormatter2 = [[NSDateFormatter alloc] init];
[dateFormatter2 setDateFormat:#"MM/dd/yyyy"];
NSDate *enddate2 = [dateFormatter2 dateFromString: date2.text];
int start1 = [startdate1 timeIntervalSince1970];
int end2 = [enddate2 timeIntervalSince1970];
double difference12 = end2-start1;
int days12;
days12 =(int)((double)difference12/(3600.0*24.00)+1);
result12.text = [[NSString alloc] initWithFormat:#"%i", days12]

If you use NSCalendar, you won't need to deal with Daylight Savings Time calculation.
int days = [[[NSCalendar currentCalendar] components:NSDayCalendarUnit
fromDate:startDate1
toDate:endDate2
options:0] day] + 1;

Most like this is a daylight savings issue (March 11th, 2012). Set the date formatters' timezones to:
[NSTimeZone timeZoneForSecondsFromGMT:0];
This should fix the issue.

To add to others, please do not rely on number of seconds in a day being 86400 all the time, it won't. Be sure to watch Session 211 Performing Calendar Calculations from WWDC 2011.

You can think of NSDate as a point in time. If you want to calculate number of days between two dates, this is a calendar issue and there are more than one calendars (like the Mayan calendar).
What you need is NSDateComponents:
NSDate *dateToday = [NSDate date];
NSDateComponents *dateBComponent = [[NSDateComponents alloc] init];
[dateBComponent setDay:-10];
NSDate *date10DaysAgo = [[NSCalendar currentCalendar] dateByAddingComponents:dateBComponent
toDate:dateToday
options:0];
NSCalendar *calendar = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease];
NSDateComponents *components = [calendar components:NSDayCalendarUnit
fromDate:date10DaysAgo
toDate:dateToday
options:0];
NSLog(#"Difference: %d", components.day);

Related

Age extracted from birth date always off by inconsistent amount

I'm using the following code to convert a user-supplied birthdate to its equivalent years from the current date. The output is always off by an inconsistent amount in years and very large numbers in days and months.
NSDateFormatter *tempFormatter = [[NSDateFormatter alloc] init];
[tempFormatter setDateFormat:#"yyyy-mm-dd hh:mm:ss"];
NSDate *birthDate = [tempFormatter dateFromString:[NSString stringWithFormat:#"%#-%#-%# 01:00:00",self.birthYear.text,self.birthMonth.text,self.birthDay.text]];
NSDate* now = [NSDate date];
NSDateComponents* ageComponents = [[NSCalendar currentCalendar]
components:NSYearCalendarUnit
fromDate:birthDate
toDate:now
options:0];
NSInteger years = [ageComponents year];
NSInteger days = [ageComponents day];
NSInteger months = [ageComponents month];
NSLog(#"Years: %ld, Days: %ld, Months: %ld",years,days, months);
What gets outputted when I input "06-16-1986" is the following
Years: 28, Days: 9223372036854775807, Months: 9223372036854775807
The year is off by 1 and the months and days are producing extremely large numbers. I get the same issue using various dates. For example, "12-07-1989" produces
Years: 25, Days: 9223372036854775807, Months: 9223372036854775807
What am I doing wrong here?
the problem is in this line
NSDateComponents* ageComponents = [[NSCalendar currentCalendar]
components:NSYearCalendarUnit
fromDate:birthDate
toDate:now
options:0];
if you want month & days to be calculated you need to include that in the components like this
NSDateComponents* ageComponents = [[NSCalendar currentCalendar]
components:( NSYearCalendarUnit | NSDayCalendarUnit | NSMonthCalendarUnit)
fromDate:birthDate
toDate:now
options:0];
also your format is wrong for month string
[tempFormatter setDateFormat:#"yyyy-mm-dd hh:mm:ss"];
should be corrected as
[tempFormatter setDateFormat:#"yyyy-MM-dd hh:mm:ss"];
now you will get correct date.
explanation.
as mentioned on apple documentation these are 1-based. so incase you dont provide a value it will put 1 as default. so earlier your month format was "mm" and it was not correctly setting a month for the birthday hence it was 1986-01-16 so now its 2014-04-01 (in singapore). So you get 28 years which is correct.
Add |NSMonthCalendarUnit|NSDayCalendarUnit to your components, change the date format from yyyy-mm-dd hh:mm:ss to yyyy-MM-dd hh:mm:ss:
NSDateFormatter *tempFormatter = [[NSDateFormatter alloc] init];
[tempFormatter setDateFormat:#"yyyy-MM-dd hh:mm:ss"];
NSDate *birthDate = [tempFormatter dateFromString:[NSString stringWithFormat:#"%#-%#-%# 01:00:00",#"2000", #"04",#"01"]];
NSDate* now = [NSDate date];
NSDateComponents* ageComponents = [[NSCalendar currentCalendar]
components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit
fromDate:birthDate
toDate:now
options:0];
NSInteger years = [ageComponents year];
NSInteger days = [ageComponents day];
NSInteger months = [ageComponents month];
NSLog(#"Years: %d, Days: %d, Months: %d",years,days, months);

Get number of days between two NSDate dates in a particular timezone

I found the codes to calculate days difference between two dates here.
I write a method :
-(NSInteger)daysWithinEraFromDate:(NSDate *) startDate toDate:(NSDate *) endDate
{
NSCalendar *gregorian = [[NSCalendar alloc]
initWithCalendarIdentifier:NSGregorianCalendar];
NSInteger startDay=[gregorian ordinalityOfUnit:NSDayCalendarUnit
inUnit: NSEraCalendarUnit forDate:startDate];
NSInteger endDay=[gregorian ordinalityOfUnit:NSDayCalendarUnit
inUnit: NSEraCalendarUnit forDate:endDate];
return endDay-startDay;
}
This method has a problem: it can't consider the timezone thing. Even I add a line like this:
[gregorian setTimeZone:[NSTimeZone localTimeZone]];
My test code is like this:
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:#"yyyy-MM-dd HH:mm:ss"];
NSString *strDate = #"2012-09-03 23:00:00";
NSDate *dateStart = [dateFormat dateFromString:strDate];
strDate = #"2012-09-04 01:00:00";
NSDate *dateEnd = [dateFormat dateFromString:strDate];
NSLog(#"Days difference between %# and %# is: %d days",[dateFormat stringFromDate:dateStart],[dateFormat stringFromDate:dateEnd],[self daysWithinEraFromDate:dateStart toDate:dateEnd]);
The result is:
Days difference between 2012-09-03 23:00:00 and 2012-09-04 01:00:00 is: 0 days
I want to get 1 day as result by the number of midnights between the two dates. My timezone is GMT +8. But this calculation is based on GMT, so I get the wrong days number. Is there anyway to solve this problem? Thank you.
Scott Lemmon's method can solve my problem. I rewrite my code like this:
-(NSInteger)daysWithinEraFromDate:(NSDate *) startDate toDate:(NSDate *) endDate
{
NSCalendar *gregorian = [[NSCalendar alloc]
initWithCalendarIdentifier:NSGregorianCalendar];
[gregorian setTimeZone:[NSTimeZone localTimeZone]];
NSDate *newDate1 = [startDate dateByAddingTimeInterval:[[NSTimeZone localTimeZone] secondsFromGMT]];
NSDate *newDate2 = [endDate dateByAddingTimeInterval:[[NSTimeZone localTimeZone] secondsFromGMT]];
NSInteger startDay=[gregorian ordinalityOfUnit:NSDayCalendarUnit
inUnit: NSEraCalendarUnit forDate:newDate1];
NSInteger endDay=[gregorian ordinalityOfUnit:NSDayCalendarUnit
inUnit: NSEraCalendarUnit forDate:newDate2];
return endDay-startDay;
}
If the time zone offset isn't working, how about just add or subtract it manually instead?
In your case NSDate *newDate = [oldDate dateByAddingTimeInterval:(-8 * 60 * 60)]; to subtract off your +8 hours.
Or if you want to find the GMT offset automatically as well then it would simply be NSDate *newDate = [oldDate dateByAddingTimeInterval:(-[[NSTimeZone localTimeZone] secondsFromGMT])
Another thought:
A perhaps easier solution would be to just disregard the time information altogether. Just set it to the same arbitrary number for both dates, then as long as the dates come from the same timezone you will always get the correct number of mid-nights between them, regardless of GMT offset.
What you really want is the NSDate method timeIntervalSinceDate:, and take that result and if it's more than 0 but less than 86400 (the number of seconds in a day), that's one day. Otherwise, divide your result by 86400 and you'll get the number of days.
The way you currently have your code, there's only 2 hours between the two days and that's why you are seeing a result of 0 and not one.
Edit - and to determine if midnight has happened, let's try this function I just wrote off the top of my head:
- (NSDate *) getMidnightDateFromDate: (NSDate *) originalDate
{
NSDateComponents *components = [[NSCalendar currentCalendar] components:NSIntegerMax fromDate:originalDate];
[components setHour:0];
[components setMinute:0];
[components setSecond:0];
NSDate *midnight = [[NSCalendar currentCalendar] dateFromComponents:components];
return(midnight);
}
- (BOOL) howManyDaysDifferenceBetween: startDate and: endDate
{
NSDate * firstMidnight = [self getMidnightDateFromDate: startDate];
NSDate * secondMidnight = [self getMidnightDateFromDate: endDate];
NSTimeInterval timeBetween = [firstMidnight timeIntervalSinceDate: secondMidnight];
NSInteger numberOfDays = (timeBetween / 86400);
return(numberOfDays);
}
which I'm basing off Dave Delong's answer to this question. No guarantees that my code will work (I didn't test it), but I think the concept is sound.

NSString parse to find date

I am pulling information from a database that contains dates formatted weird.
When they are pulled they are in the format of:
DayOfWeek, Month Date
I am attempting to use EventKit to have the option to add the date to the users calendar.
I can't seem to find the best way to go about doing this.
Any help or point in the right direction would be very much appreciated!!
You want to use an NSDateFormatter:
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.dateFormat = #"EEEE, MMMM d";
NSDate *date = [dateFormatter dateFromString:#"Tuesday, March 3"];
"DayOfWeek, Month Date" is ambiguous, so I did my best to guess what you meant. If I was wrong, you'll need to change the format string a bit. Here is a reference on the strings you can use.
Your problem is that this database has ambiguous dates. It does not have a year information.
NSDateFormatters don't guess date information. They create dates from the information you provide. And since this information is missing the year will be 1970 (as in: the same year as the reference data).
Because the format that is saved in the database is totally stupid I assume that those dates always are within the next 365 days. So in theory you wouldn't have to save a year info.
You could then use something like this to figure out the NSDate from that totally ambiguous date information.
The idea is to transfer the date from 1970 (created from your string) to the current year. And if it would be in the past for current year (e.g. today is 31 March a date with "Foo, March 30" would be in the past) move it to next year.
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.dateFormat = #"EEEE, MMMM d";
// the following line is important if you want that your code runs on device that are not english!
dateFormatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:#"en_US"];
NSDate *date = [dateFormatter dateFromString:#"Wednesday, March 30"];
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *components = [calendar components:NSMonthCalendarUnit|NSDayCalendarUnit fromDate:date];
NSDateComponents *todayComponent = [calendar components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit fromDate:[NSDate date]];
NSInteger proposedYear = [todayComponent year];
// if supposed date would be in the past for the current year move it into next year
if ([components month] < [todayComponent month]) {
proposedYear++;
}
if ([components month] == [todayComponent month] && [components day] < [todayComponent day]) {
proposedYear++;
}
[components setYear:proposedYear];
date = [calendar dateFromComponents:components];
// just for logging, so you are sure that you use the correct year:
[dateFormatter setDateFormat:#"EEEE, MMMM d yyyy"];
NSLog(#"%#", [dateFormatter stringFromDate:date]);

Struggling to store a date for later use

Hi I'm very new to iOS programming and am playing around with dates (todays date and a date 1 year from now).
Here's the code i'm dabbling with.
NSCalendar * calendar = [NSCalendar currentCalendar];//Create a calendar
NSDate *todaysDate = [[NSDate alloc]init]; //get todays date
NSString *dateToday = [NSString stringWithFormat:#"%#",todaysDate];//convert it to a string
NSDateFormatter *df = [[NSDateFormatter alloc] init];// create a formatter
[df setDateFormat:#"yyyy-MM-dd HH:mm:ss ZZZ" ];//input how the date looks as a string
myDate = [df dateFromString: dateToday];// change it back to a proper NSDate
NSDateComponents *components = [[NSDateComponents alloc] init]; // create the components
[components setYear:1];//add 1 year
nextYear = [calendar dateByAddingComponents:components toDate:todaysDate options:0]; // build the year from component into a variable
dateNextYear = [NSString stringWithFormat:#"%#",nextYear];//convert it to a string
NSDateFormatter *yearFormat = [[NSDateFormatter alloc] init];// create a formatter
[yearFormat setDateFormat:#"yyyy-MM-dd HH:mm:ss ZZZ" ];//input how the date looks as a string
myDateInTheFuture = [yearFormat dateFromString: dateNextYear];// change it back to a proper NSDate
NSLog(#" next years date is %# ", myDateInTheFuture);
[yearFormat release];
[components release];
[todaysDate release];
I can get the current date and the future date 1 year from now, but i'm unsure how i would store the future date for comparison, i know i can use the "compare" item for NSDate to check, but when i set the future date to a variable every time it runs it stays relative 1 year apart from what i'm checking it against which is todays date.
Its 3am where i am and my brain is mush so apologises in advance if this is the simplest thing ever and i just can't see it.
Its my first post so go easy on me please.
Thanks
I am not entirely sure what you are trying to do, but this is what I gather:
You want to take the current date, add a year to it, and manipulate the resulting date.
Please notify me if this is not correct.
For this, try the following:
NSDate *todayDate = [NSDate date]; //Create a date that is set to today
NSDate *resultingDate = [calendar dateByAddingTimeInterval:31556926; //Take the current date and add the amount of seconds in a year to it
If you want to store this permanently, use the NSUserDefaults:
to set:
[userDefaults setObject:resultingDate forKey:#"storedDate"];
Hope this helps,
HBhargava
to get:
NSDate *returnedDate = [userDefaults dateForKey:#"storedDate"];

Workout difference in months in Objective C

I would like to work out the difference in months
at the moment I have this code:
dateInterval = [endDate timeIntervalSinceDate:startDate];
But that returns a value in seconds, I would like to see the difference between the dates in months.
How would I do this?
Thanks
NSDateFormatter *inputFormatter = [[NSDateFormatter alloc] init];
[inputFormatter setDateFormat:#"dd/MM/yyyy"];
NSDate *startDate = [inputFormatter dateFromString:#"07/03/2011"];
NSDate *endDate = [inputFormatter dateFromString:#"07/06/2011"];
NSInteger month_delta = [[[NSCalendar currentCalendar] components: NSMonthCalendarUnit fromDate: startDate toDate: endDate options: 0] month];
NSLog(#"---------------------------->>%d", month_delta);
[inputFormatter release]; // <-- in case not using ARC
it will log:
---------------------------->>3
You can create a NSDateComponents from the NSDates in question and just subtract the total months. (Total months = 12*year+currentMonth)
http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSDateComponents_Class/Reference/Reference.html#//apple_ref/occ/cl/NSDateComponents