2

这是一个谜题。我使用以下方法来计算今天日期和即将到来的生日之间的天数:

-(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];

}

一切正常,但结果不准确!我经常发现离今天很近但相隔一天的生日导致[differenceDays day]是一样的!即,如果今天是 2011 年 6 月 6 日并且我有两个生日,一个在 2011 年 6 月 7 日,另一个在 2011 年 6 月 8 日,那么它们都显示为 1 天后!

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

非常感谢。

4

3 回答 3

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 日出生,则增加一年将产生 3 月 1 日,一旦您再次进入闰年,这将是错误的。通过每次从原始日期跳转,我们没有这个问题。

于 2011-06-06T00:09:06.210 回答
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;
于 2011-06-06T02:44:47.247 回答
1

我想我已经找到了解决办法。仔细检查输出,似乎都归结为 HOURS 的差异。例如:将今天与明天的日期进行比较可能最终会相差 18 小时。这导致 [difference day] 被设置为 0,即它认为明天就是今天,因为距离它不到 24 小时。

您可以在下面看到修复。我取小时数,例如 18 并除以 24(得到天数)。在这种情况下,18/24 = 0.75。然后我将其四舍五入,即“1”。因此,虽然 [difference days] 认为明天就是今天,但通过四舍五入时间,你知道实际上就是明天。

 -(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];



 }  
于 2011-06-08T20:58:28.953 回答