7

I'm trying to get the number of days in a current year.

When I try the solution on Number of days in the current month using iPhone SDK?, and replace NSMonthCalendarUnit by NSYearCalendarUnit, I still get the number of days for that month.

Does anyone know how I should do this?

Thanks in advance for your help.

Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
nicoko
  • 195
  • 1
  • 2
  • 9

5 Answers5

8

Here's a super accurate NSCalendar extension in Swift 2:

extension NSCalendar {
    func daysInYear(date: NSDate = NSDate()) -> Int? {
        let year = components([NSCalendarUnit.Year], fromDate: date).year
        return daysInYear(year)
    }

    func daysInYear(year: Int) -> Int? {
        guard let begin = lastDayOfYear(year - 1), end = lastDayOfYear(year) else { return nil }
        return components([NSCalendarUnit.Day], fromDate: begin, toDate: end, options: []).day
    }

    func lastDayOfYear(year: Int) -> NSDate? {
        let components = NSDateComponents()
        components.year = year
        guard let years = dateFromComponents(components) else { return nil }

        components.month = rangeOfUnit(NSCalendarUnit.Month, inUnit: NSCalendarUnit.Year, forDate: years).length
        guard let months = dateFromComponents(components) else { return nil }

        components.day = rangeOfUnit(NSCalendarUnit.Day, inUnit: NSCalendarUnit.Month, forDate: months).length

        return dateFromComponents(components)
    }
}

You can use it like this:

let calendar = NSCalendar.currentCalendar() // I'm using the Gregorian calendar
calendar.daysInYear()     // 365 (since it's currently 2015)
calendar.daysInYear(2016) // 366 (leap year!)

This is super flexible since we don't assume anything about the length of the calendar:

let hebrew = NSCalendar(calendarIdentifier: NSCalendarIdentifierHebrew)
hebrew?.daysInYear(-7)   // 354
hebrew?.daysInYear(-100) // 384

Enjoy.

Sam Soffes
  • 14,831
  • 9
  • 76
  • 80
  • Another approach would be to get the months in the given year and then enumerate each month and add up the days. I'm not sure which is more accurate or more efficient. I'd assume my current approach is the most efficient. No idea if it's more accurate to do it the other way though. Time is hard. – Sam Soffes Aug 14 '15 at 07:43
5

If you're only going to use the Gregorian Calender, you can calculate it manually.

http://en.wikipedia.org/wiki/Leap_year#Algorithm

if year modulo 400 is 0 then leap
 else if year modulo 100 is 0 then no_leap
 else if year modulo 4 is 0 then leap
 else no_leap
kubi
  • 48,104
  • 19
  • 94
  • 118
  • 2
    Calculating days in year is simple enough, but in general I would recommend going with the date/time libraries available. Doing date/time calculations manually will always come back and bite you somehow... – Krumelur Jun 30 '13 at 08:07
  • I'd strongly recommend against this. Time is super complicated. If you need your stuff to work in other locales that might not use the Gregorian calendar or need to work in the distant past (again not Gregorian) this won't work. NSCalendar is great for solving these sort of things. – Sam Soffes Aug 14 '15 at 08:01
5

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.

Godisemo
  • 1,813
  • 2
  • 18
  • 26
1

Use the NSCalendar and NSDateComponent classes, like this:

long GetDaysInYear(int year) {
    NSDateComponents* c = [[NSDateComponents alloc] init];
    c.year = year;
    NSCalendar* cal = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
    NSDate* startDate = [cal dateFromComponents:c];
    c.year += 1;
    NSDate* endDate = [cal dateFromComponents:c];
    return [cal components:NSDayCalendarUnit fromDate:startDate toDate:endDate options:0].day;
}
Krumelur
  • 31,081
  • 7
  • 77
  • 119
0

As example:

func daysInYear(year: Int) -> Int {
   var calendar = NSCalendar(calendarIdentifier: NSGregorianCalendar)
   var b = NSDate.dateWithNaturalLanguageString("01.01.\(year)", locale: NSLocale.currentLocale()) as! NSDate
   var e = NSDate.dateWithNaturalLanguageString("12.31.\(year)", locale: NSLocale.currentLocale()) as! NSDate

   return calendar!.components(NSCalendarUnit.CalendarUnitDay, fromDate: b, toDate: e, options: nil).day + 1 
}

But default days return 355 and 354 this caused (may be) that counting begin from zero :)

iTux
  • 1,946
  • 1
  • 16
  • 20
  • It's one less since you start from day one. If you do from 12/31 to 12/31, that is a full year :) – Sam Soffes Aug 14 '15 at 07:12
  • I think year started from 01.01.2015 00:00:00 (000) and finished to 31.12.2015 23:59:59 (99) :)) – iTux Aug 17 '15 at 10:34