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

}

すべてが機能しますが、結果は正確ではありません! 今日に近い誕生日でも 1 日離れていると [differenceDays day] が同じになることがよくあります。つまり、今日が 2011 年 6 月 6 日で、2 つの誕生日があり、1 つは 2011 年 6 月 7 日で、もう 1 つは 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;

基本的には、今日と目標日が 1 年のうちどれだけ離れているかを計算し (つまり、今日 [6 月 5 日] は 1 年で 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 年増やすと 3 月 1 日になります。毎回元の日付からジャンプすることで、この問題は発生しません。

于 2011-06-06T00:09:06.210 に答える
2

私は自分のアプリの1つでまったく同じことをしています。これが私がそれを行う方法です:

//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 に答える