iPhone:计算到下一个生日的天数的方法不准确 - ?

时间:2011-06-05 23:51:57

标签: iphone date calendar nsdatecomponents

这是一个益智游戏。我使用以下内容计算今天的日期和即将到来的生日之间的天数:

-(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并且我有两个生日,一个在2011年6月7日和另一个2011年6月8日,那么它们都显示为1天之后!

任何人都有更好的方法来准确计算这个,或者可以发现问题吗?

非常感谢。

3 个答案:

答案 0 :(得分:4)

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;

基本上,我们正在计算今天到目前为止的年份和目标日期(即今天[6月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.

更新我将上面的循环更新为始终从原始日期 n 年增加,而不是逐年增加。如果有人在2月29日出生,增加一年就会产生1月1日,一旦你再次闰年就会出错。每次跳过原始日期,我们都没有这个问题。

答案 1 :(得分:2)

我在其中一个应用中执行完全相同的操作。我是这样做的:

//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;

答案 2 :(得分:1)

我想我找到了解决方案。仔细检查输出,似乎都归结为HOURS的差异。例如:比较今天和明天的日期可能最终会比较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];



 }