这是一个益智游戏。我使用以下内容计算今天的日期和即将到来的生日之间的天数:
-(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天之后!
任何人都有更好的方法来准确计算这个,或者可以发现问题吗?
非常感谢。
答案 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];
}