Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I calculate the number of days in this year in Objective C

How can i calculate the number of days in a year for any calendar, not just gregorian. I have tried this

NSUInteger *days = [[NSCalendar currentCalendar] rangeOfUnit:NSDayCalendarUnit inUnit:NSYearCalendarUnit forDate:[NSDate date]];

but that gives me the number of days in the current month instead of the number of days in the current year.

like image 351
Godisemo Avatar asked Jan 16 '10 18:01

Godisemo


5 Answers

I finally came up with a solution that works. What I do is first calculate the number of months in the year and then for each month calculate the number of days for that month.

The code looks like this:

NSUInteger days = 0;
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDate *today = [NSDate date];
NSDateComponents *components = [calendar components:NSYearCalendarUnit fromDate:today];
NSUInteger months = [calendar rangeOfUnit:NSMonthCalendarUnit
                                   inUnit:NSYearCalendarUnit
                                  forDate:today].length;
for (int i = 1; i <= months; i++) {
    components.month = i;
    NSDate *month = [calendar dateFromComponents:components];
    days += [calendar rangeOfUnit:NSDayCalendarUnit
                           inUnit:NSMonthCalendarUnit
                          forDate:month].length;
}

return days;

It is not as neat as I would have hoped for but it will work for any calendar such as the ordinary gregorian one or the islamic one.

like image 53
Godisemo Avatar answered Nov 08 '22 13:11

Godisemo


In general you may use number of days between 1st day of the year and 1st day of the next year. Here's the code that illustrates this approach

- (NSDate *)firstDateOfYear:(NSInteger)year
{
    NSDateComponents *dc = [[NSDateComponents alloc] init];
    dc.year = year;
    dc.month = 1;
    dc.day = 1;
    return [[NSCalendar currentCalendar] dateFromComponents:dc];
}

- (NSUInteger)numberOfDaysInYear:(NSInteger)year
{
    NSDate *firstDateOfYear = [self firstDateOfYear:year];
    NSDate *firstDateOfNextYear = [self firstDateOfYear:year + 1];
    NSDateComponents *components = [[NSCalendar currentCalendar] components:NSDayCalendarUnit fromDate:firstDateOfYear toDate:firstDateOfNextYear options:0];
    return [components day];
}
like image 26
Olex Avatar answered Nov 08 '22 15:11

Olex


I don't know objective-c but it is a simple algorithm to determine if it is a leap year.

if ( year % 400 == 0 )
   then 366 // Leap Year
else if ( year % 100 == 0 )
   then 365 // Non-Leap Year
else if ( year % 4 == 0 )
   then 366 // Leap Year
else
   365 // Non-Leap Year

Or if you want a little less verbose version

if ((year % 4 == 0) && (year % 100 != 0) || (year % 400 == 0))
   then 366 // Leap Year
else
   365 // Non-Leap Year
like image 4
William Clemens Avatar answered Nov 08 '22 13:11

William Clemens


I don't know if anybody is still interested in this thread, but is another possible solution:

NSCalendar *calendar = [NSCalendar currentCalendar];
NSDate *startOfYear;
NSTimeInterval lengthOfYear;
[calendar rangeOfUnit:NSYearCalendarUnit
            startDate:&startOfYear
             interval:&lengthOfYear
              forDate:[NSDate date]];
NSDate *endOfYear = [startOfYear dateByAddingTimeInterval:lengthOfYear];
NSDateComponents *comp = [calendar components:NSDayCalendarUnit
                                     fromDate:startOfYear
                                       toDate:endOfYear
                                      options:0];
NSUInteger numberOfDaysInThisYear = [comp day];

using only 2 calls to NSCalendar.

like image 2
Martin R Avatar answered Nov 08 '22 15:11

Martin R


Maybe you can use the components:fromDate:toDate:options: selector which is meant to (and I quote official Apple docs): Returns, as an NSDateComponents object using specified components, the difference between two supplied dates. ?

Also read this post that clarifies the behaviour you are seeing.

like image 1
Jonas Van der Aa Avatar answered Nov 08 '22 15:11

Jonas Van der Aa