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] range
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];
}
In order to do what you want you have to find the range of days in a month and months in a year for a specific calendar. This function will do what you need for any calendar that uses day/month/year units (or has some equivalent mapped):
NSInteger getDaysInYear(NSDate* date)
{
// Get the current calendar
NSCalendar* c = [NSCalendar currentCalendar];
// Find the range for days and months in this calendar
NSRange dayRange = [c rangeOfUnit:NSDayCalendarUnit inUnit:NSYearCalendarUnit forDate:date];
NSRange monthRange = [c rangeOfUnit:NSMonthCalendarUnit inUnit:NSYearCalendarUnit forDate:date];
// Get the year from the suppled date
NSDateComponents* yearComps = [c components:NSYearCalendarUnit fromDate:date];
NSInteger thisYear = [yearComps year];
// Create the first day of the year in the current calendar
NSUInteger firstDay = dayRange.location;
NSUInteger firstMonth = monthRange.location;
NSDateComponents* firstDayComps = [[[NSDateComponents alloc] init] autorelease];
[firstDayComps setDay:firstDay];
[firstDayComps setMonth:firstMonth];
[firstDayComps setYear:thisYear];
NSDate* firstDayDate = [c dateFromComponents:firstDayComps];
// Create the last day of the year in the current calendar
NSUInteger lastDay = dayRange.length;
NSUInteger lastMonth = monthRange.length;
NSDateComponents* lastDayComps = [[[NSDateComponents alloc] init] autorelease];
[lastDayComps setDay:lastDay];
[lastDayComps setMonth:lastMonth];
[lastDayComps setYear:thisYear];
NSDate* lastDayDate = [c dateFromComponents:lastDayComps];
// Find the difference in days between the first and last days of the year
NSDateComponents* diffComps = [c components:NSDayCalendarUnit
fromDate:firstDayDate
toDate:lastDayDate
options:0];
// We have to add one since this was subtraction but we really want to
// give the total days in the year
return [diffComps day] + 1;
}
If you want to specify this year, you can call it simply as getDaysInYear([NSDate date]);
, or you could create a date from specific year/other components and pass that. You could also very easily re-implement it as a method call.
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
Best solution found for this problem using SWIFT 5.3 and Xcode 12.
Put it into playgrounds, call the checkLeapYear function passing a year into it and play around.
func checkLeapYear(year: Int) {
if year % 4 == 0{
if year % 100 == 0 {
if year % 400 == 0{
print("\(year) is a Leap Year!")
} else {
print("\(year) is NOT a Leap Year!")
}
} else {
print("\(year) is a Leap Year!")
}
} else {
print("\(year) is NOT a Leap Year!")
}
}
The algorithm is quite tricky so I suggest you use the following logic when performing it on your own:
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.
[[NSCalendar currentCalendar] ordinalityOfUnit:NSYearCalendarUnit
inUnit:NSEraCalendarUnit forDate:date];