mkz
mkz

Reputation: 2302

NSCalendar gives wrong week numbers by month in year

I have a function which returns an array of week numbers due to month and year.

Here is the code:

let calendar = NSCalendar.currentCalendar()
let weekRange = calendar.rangeOfUnit(NSCalendarUnit.CalendarUnitWeekOfYear, inUnit: .CalendarUnitMonth, forDate: NSDate())
weekArray = Array(weekRange.location..<weekRange.location + weekRange.length)

Example: for 2015-08-21 it will return [31, 32, 33, 34, 35, 36] which is correct due to this website.

It works fine when but I found one mistake if I pass this date "2016-01-01" it returns [1, 2, 3, 4, 5] but the correct array should be [53 (from 2015 year), 1, 2, 3, 4] (again checked on this website).

As mentioned on that website:

The first week of the year (WN 1) is the week containing january 4th or the first tuesday of the Year.

So, I have to write some calculation to make it works? Or there is an easier solution? Thanks for help.

Upvotes: 2

Views: 1231

Answers (1)

vadian
vadian

Reputation: 285069

The result depends on calendar type, locale and first weekday of week settings.

The calendar on the mentioned website is based on ISO 8601, your currentCalendar() probably on Gregorian, both types are similar but not identical.

Please check this out in a playground and try also to uncomment the commented line and provide other locale identifiers.

The code is for Swift 2.0, in Swift 1.2 use .CalendarUnitWeekOfYear and .CalendarUnitMonth

let components = NSDateComponents()
components.year = 2016
components.month = 1

var weekNumbersForCalendarIdentifier = { ( identifier : String) -> [Int] in
  let calendar = NSCalendar(calendarIdentifier: identifier)!
  // calendar.locale = NSLocale(localeIdentifier: "us_POSIX")
  let weekRange = calendar.rangeOfUnit(.WeekOfYear, inUnit: .Month, forDate: calendar.dateFromComponents(components)!)
  return Array(weekRange.location..<weekRange.location + weekRange.length)
}

let resultISO = weekNumbersForCalendarIdentifier(NSCalendarIdentifierISO8601)
let resultGregorian = weekNumbersForCalendarIdentifier(NSCalendarIdentifierGregorian)

There is one particular behavior independent of the different settings:

NSCalendar displays the ordinal number 0 rather than the actual number 52 or 53 of the preceding year.

Upvotes: 5

Related Questions