iPhone: метод подсчета дней до следующего дня рождения не точен -? - PullRequest
2 голосов
/ 06 июня 2011

Вот загадка.Я использую следующее для вычисления количества дней между сегодняшней датой и предстоящим днем ​​рождения:

-(int) daysTillBirthday: (NSDate*)aDate {

// check to see if valid date was passed in

//NSLog(@"aDate passed in is %@",aDate);

if (aDate == nil) {
    //NSLog(@"aDate is NULL");
    return -1;  // return a negative so won't be picked in table
}

//** HOW MANY DAYS TO BDAY

NSDate *birthDay = aDate; // [calendar dateFromComponents:myBirthDay];

//NSLog(@"birthDay: %@, today: %@",birthDay, [NSDate date]);

NSCalendar *calendar = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease];

NSDateComponents *thisYearComponents = [calendar components:NSYearCalendarUnit fromDate:[NSDate date]];
NSDateComponents *birthDayComponents = [calendar components:NSMonthCalendarUnit|NSDayCalendarUnit fromDate:birthDay];
[birthDayComponents setYear:[thisYearComponents year]];

NSDate *birthDayThisYear = [calendar dateFromComponents:birthDayComponents];

//NSLog(@"birthDayThisYear: %@",birthDayThisYear);

NSDateComponents *differenceHours = [calendar components:NSHourCalendarUnit fromDate:[NSDate date] toDate:birthDayThisYear options:0];
NSDateComponents *differenceDays = [calendar components:NSDayCalendarUnit fromDate:[NSDate date] toDate:birthDayThisYear options:0];

// NSLog(@"difference days: %i, hours %i",[differenceDays day],[differenceHours hour]);

//*** I added this to try and correct the "error" *** 

if ([differenceDays day] == 0) {  // is it today, or tomorrow?

    if (([differenceHours hour] <= 0) && ([differenceHours hour] >= -24)) {  // must be today

        //NSLog(@"TODAY");
        return (0);            
        [calendar release];

    }else if (([differenceHours hour] >= 0) && ([differenceHours hour] <= 24)) { 

        //NSLog(@"TOMORROW");
        return (1);
        [calendar release];

    }           
}

if ([differenceDays day] < 0) {
    // this years birthday is already over. calculate distance to next years birthday
    [birthDayComponents setYear:[thisYearComponents year]+1];
    birthDayThisYear = [calendar dateFromComponents:birthDayComponents];
    differenceDays = [calendar components:NSDayCalendarUnit fromDate:[NSDate date] toDate:birthDayThisYear options:0];
}


return ([differenceDays day]);
[calendar release];

}

Все работает, но результаты не точны!Я часто нахожу, что дни рождения, которые близки к сегодняшнему дню, но на расстоянии одного дня, приводят к тому, что [день различия дней] остается тем же!то есть, если сегодня 6/6/2011, и у меня есть два дня рождения, один 6 июня 2011 года и другой 6 августа 2011 года, то оба они показываются как 1 день!методы для точного расчета этого, или может определить проблему?

Большое спасибо.

Ответы [ 3 ]

4 голосов
/ 06 июня 2011

NSCalendar предоставляет гораздо более простой способ сделать это:

NSDate *birthday = ...; // the birthday
NSDate *today = [NSDate date];

NSCalendar *c = [NSCalendar currentCalendar];
NSInteger birthdayDayOfYear = [c ordinalityOfUnit:NSDayCalendarUnit inUnit:NSYearCalendarUnit forDate:birthday];
NSInteger todayDayOfYear = [c ordinalityOfUnit:NSDayCalendarUnit inUnit:NSYearCalendarUnit forDate:today];

NSInteger different = birthdayDayOfYear - todayDayOfYear;

По сути, мы выясняем, насколько далеко зашли сегодняшний год и целевая дата (т. Е. Сегодня [5 июня])156-й день года), а затем вычтите их, чтобы выяснить, сколько дней между ними.

Этот метод, конечно, основан на предположении, что целевая дата находится в том же году, что итекущая дата.Я думаю, что было бы довольно легко обойти это, однако.


Другой, еще более простой способ сделать это, который будет учитывать многолетние различия, выглядит так:

NSDateComponents *d = [[NSCalendar currentCalendar] components:NSDayCalendarUnit fromDate:today toDate:birthday options:0];
NSInteger difference = [d day];

Если вам нужно убедиться, что день рождения в будущем, это также легко сделать:

NSDateComponents *year = [[[NSDateComponents alloc] init] autorelease];
NSInteger yearDiff = 1;
NSDate *newBirthday = birthday;
while([newBirthday earlierDate:today] == newBirthday) {
  [year setYear:yearDiff++];
  newBirthday = [[NSCalendar currentCalendar] dateByAddingComponents:year toDate:birthday options:0];
}
//continue on with the 2-line calculation above, using "newBirthday" instead.

update Я обновил цикл выше, чтобы всегда увеличиватьот первоначальной даты n лет, а не год за годом.Если кто-то родится 29 февраля, увеличение на один год приведет к 1 марта, что было бы неправильно, если бы вы снова попали в високосный год.Прыгая с первоначальной даты каждый раз, у нас нет этой проблемы.

2 голосов
/ 06 июня 2011

Я делаю то же самое в одном из моих приложений. Вот как я это делаю:

//This is the date your going to - in your case the birthday - note the format
NSString *myDateAsAStringValue = @"20110605";

// Convert string to date object
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:@"yyyyMMdd"];
NSDate *newDate = [dateFormat dateFromString:myDateAsAStringValue];  

NSDateComponents *dateComp = [[NSDateComponents alloc] init];

NSCalendar *Calander = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];


NSDateComponents *comps=[[NSDateComponents alloc] init];

unsigned int unitFlags = NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit;

dateComp = [Calander components:unitFlags fromDate:[NSDate date]];

[dateFormat setDateFormat:@"dd"];
[comps setDay:[[dateFormat stringFromDate:[NSDate date]] intValue]];
[dateFormat setDateFormat:@"MM"];
[comps setMonth:[[dateFormat stringFromDate:[NSDate date]] intValue]];
[dateFormat setDateFormat:@"yyyy"];
[comps setYear:[[dateFormat stringFromDate:[NSDate date]] intValue]];
[dateFormat setDateFormat:@"HH"];
[comps setHour:05];
[dateFormat setDateFormat:@"mm"];
[comps setMinute:30];

NSDate *currentDate=[Calander dateFromComponents:comps];

dateComp = [Calander components:unitFlags fromDate:newDate];

[dateFormat setDateFormat:@"dd"];
[comps setDay:[[dateFormat stringFromDate:newDate] intValue]];
[dateFormat setDateFormat:@"MM"];
[comps setMonth:[[dateFormat stringFromDate:newDate] intValue]];
[dateFormat setDateFormat:@"yyyy"];
[comps setYear:[[dateFormat stringFromDate:newDate] intValue]];
[dateFormat setDateFormat:@"HH"];
[comps setHour:05];
[dateFormat setDateFormat:@"mm"];
[comps setMinute:30];

NSDate *reminderDate=[Calander dateFromComponents:comps];


NSTimeInterval ti = [reminderDate timeIntervalSinceDate:currentDate];

int days = ti/86400;
return days;
1 голос
/ 09 июня 2011

Я думаю, что нашел решение.Тщательно проверяя вывод, кажется, все сводится к разнице в ЧАСАХ.Например: сравнение сегодняшнего дня с завтрашней датой может закончиться, скажем, через 18 часов.Это приводит к тому, что [день разницы] устанавливается на 0, то есть он думает, что завтра сегодня, потому что до него осталось менее 24 часов.

Вы можете увидеть исправление ниже.Я беру количество часов, например, 18, и делю на 24 (чтобы получить количество дней).В этом случае 18/24 = 0,75.Затем я округляю это число до 1.Таким образом, хотя [разные дни] думают, что завтра сегодня, а если сложить часы, вы знаете, что это действительно завтра.

 -(int) daysTillBirthday: (NSDate*)aDate {

// check to see if valid date was passed in

//NSLog(@"aDate passed in is %@",aDate);

if (aDate == nil) {
    //NSLog(@"aDate is NULL");
    return -1;  // return a negative so won't be picked in table
}

//** HOW MANY DAYS TO BDAY

NSDate *birthDay = aDate; // [calendar dateFromComponents:myBirthDay];

NSCalendar *calendar = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease];

NSDateComponents *thisYearComponents = [calendar components:NSYearCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit  fromDate:[NSDate date]];
NSDateComponents *birthDayComponents = [calendar components:NSMonthCalendarUnit|NSDayCalendarUnit fromDate:birthDay];

NSInteger timeNow = [thisYearComponents hour];

[birthDayComponents setYear:[thisYearComponents year]];
[birthDayComponents setHour:timeNow];

NSDate *birthDayThisYear = [calendar dateFromComponents:birthDayComponents];

//NSLog(@"today %@, birthday %@",[NSDate date],birthDayThisYear);

NSDateComponents *difference = [calendar components:NSDayCalendarUnit fromDate:[NSDate date] toDate:birthDayThisYear options:0];
NSDateComponents *differenceHours = [calendar components:NSHourCalendarUnit fromDate:[NSDate date] toDate:birthDayThisYear options:0];

double daysFromHours = ((double)[differenceHours hour])/24;  // calculate number of days from hours (and round up)
int roundedDaysFromHours = ceil(daysFromHours);

NSLog(@"daysFromHours %.02f, roundedDaysFromHours %i",daysFromHours,roundedDaysFromHours);

if ([difference day] < 0) {
    // this years birthday is already over. calculate distance to next years birthday
    [birthDayComponents setYear:[thisYearComponents year]+1];
    birthDayThisYear = [calendar dateFromComponents:birthDayComponents];
    difference = [calendar components:NSDayCalendarUnit fromDate:[NSDate date] toDate:birthDayThisYear options:0];
}


//NSLog(@"%i days until birthday", [difference day]);   

return (roundedDaysFromHours);  
[calendar release];



 }  
...