Objective-С: получение количества дней в календарном году

я использую следующее NSCalendar метод для получения количества дней в календарном году:

NSRange range = [gregorian rangeOfUnit:NSDayCalendarUnit 
                                inUnit:NSYearCalendarUnit 
                               forDate:date];

Я жду range.length возвращаемое значение типа NSRange что 365 или 366 (дней).

однако этот код возвращает range.length of 31 для значения даты 2005-06-06.

что не так с моим кодом?

это полный фрагмент кода:

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

[subArray enumerateObjectsUsingBlock:
   ^(NSDate *date, NSUInteger idx, BOOL *stop) {
   NSUInteger numberOfDays = [gregorian ordinalityOfUnit:NSDayCalendarUnit
   inUnit:NSYearCalendarUnit forDate:date];
}];

4 ответов


это вычисляет количество дней в году заданной даты:

NSDate *someDate = [NSDate date];

NSDate *beginningOfYear;
NSTimeInterval lengthOfYear;
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
[gregorian rangeOfUnit:NSYearCalendarUnit
             startDate:&beginningOfYear
              interval:&lengthOfYear
               forDate:someDate];
NSDate *nextYear = [beginningOfYear dateByAddingTimeInterval:lengthOfYear];
NSInteger startDay = [gregorian ordinalityOfUnit:NSDayCalendarUnit
                                          inUnit:NSEraCalendarUnit
                                         forDate:beginningOfYear];
NSInteger endDay = [gregorian ordinalityOfUnit:NSDayCalendarUnit
                                        inUnit:NSEraCalendarUnit
                                       forDate:nextYear];
NSInteger daysInYear = endDay - startDay;

грустное предостережение: это не работает правильно для 1582 года.

дополнение: код выше работает только правильно в течение многих лет после 1582. Например, он возвращает 365 дней за 1500 год, хотя этот год был високосным в тогдашнем юлианском календаре. Григорианский календарь начинается 15 октября 1582 года. Вычисления, сделанные по григорианскому календарю, просто не определены до этой даты. Таким образом, реализация Apple верна. Я не знаю о правильной реализации в течение многих лет до 1583 года на какао.


вот относительно чистая версия. Это категория на NSCalendar.

- (NSInteger) daysInYear:(NSInteger) year {
    NSDateComponents *dateComponents = [[NSDateComponents alloc] init];
    dateComponents.year = year;
    dateComponents.month = dateComponents.day = 1;
    NSDate *firstOfYear = [self dateFromComponents:dateComponents];
    dateComponents.year = year + 1;
    NSDate *firstOfFollowingYear = [self dateFromComponents:dateComponents];

    return [[self components:NSDayCalendarUnit
                   fromDate:firstOfYear
                     toDate:firstOfFollowingYear
                     options:0] day];    
}

спасибо AKV за указание на это -components:fromDate:toDate:options будет работать в этом случае.

это, похоже, не работает для 1582 или до, что в ответе Николая Руэ, потому что расчеты григорианского календаря просто не определены до этого.


как насчет нахождения количества дней в данном году как: хотя это не относительное решение для вопроса.

-(NSInteger)daysBetweenTwoDates:(NSDate *)fromDateTime andDate:(NSDate *)toDateTime{

    NSDate *fromDate;
    NSDate *toDate;

    NSCalendar *calendar = [NSCalendar currentCalendar];

    [calendar rangeOfUnit:NSDayCalendarUnit startDate:&fromDate interval:NULL forDate:fromDateTime];
    [calendar rangeOfUnit:NSDayCalendarUnit startDate:&toDate interval:NULL forDate:toDateTime];

    NSDateComponents *difference = [calendar components:NSDayCalendarUnit fromDate:fromDate toDate:toDate options:0];

    return [difference day]; 
}

-(void)someMethod {

    NSString *yourYear=@"2012";

    NSDate *date1 = [NSDate dateWithString:[NSString stringWithFormat:@"%@-01-01 00:00:00 +0000",yourYear]];
    NSDate *date2 = [NSDate dateWithString:[NSString stringWithFormat:@"%@-12-31 00:00:00 +0000",yourYear]];

    NSInteger numberOfDays=[self daysBetweenTwoDates:date1 andDate:date2];    

    NSLog(@"There are %ld days in between the two dates.", numberOfDays);
}            

Edit:

как dateWithString: устарел, вы можете использовать

NSDateFormatter *dateFormatter=[[NSDateFormatter alloc] init];
[dateFormatter dateFormat]=@"dd-MM-yyyy";
NSDate *date=[dateFormatter dateFromString:dateString];

в форме date1 и date2


вы получаете количество дней в месяце даты.

вы можете использовать ту же функцию и просто пройти в сроки с февраля месяца. Если диапазон.длина возвращает 28, общее количество дней в году будет 365, если он возвращает 29, то количество дней будет 366.