Brian van den heuvel
Brian van den heuvel

Reputation: 396

NSDate returns wrong week Number

I have the following code:

getWeek(addDays(Date, amount: 6))

func addDays(date: NSDate, amount: Int) -> NSDate {
    // calculation $additionalDays
    let additionalDays = amount
    // adding $additionalDays
    let components = NSDateComponents()
    components.day = additionalDays

    // important: NSCalendarOptions(0)
     let futureDate = NSCalendar.currentCalendar()
    .dateByAddingComponents(components, toDate: date, options: NSCalendarOptions(rawValue: 0))
    return futureDate!
}

func getWeek(today:NSDate)->Int? {
    let formatter = NSDateFormatter()
    formatter.dateFormat = "yyyy-MM-dd"
    let myCalendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)!
    let myComponents = myCalendar.components(.WeekOfYear, fromDate: today)
    let weekNumber = myComponents.weekOfYear
   return weekNumber
}

The date in getWeek(addDays(Date, amount: 6)) returns dec 27, 2015, 7:16PM This is correct ( next sunday) However if i try to return the week number for that date, it returns 1 whereas this should be 53. How can i get the correct week number?

Upvotes: 5

Views: 1739

Answers (4)

Brian van den heuvel
Brian van den heuvel

Reputation: 396

According to Apple Developer Technical Support:

27 Dec 2015 is week 52, not week 53. The first day of week 53 in 2015 is 28 Dec.

Regardless, you’re correct that the value returned by your getWeek() function does not match ISO 8601. The reason for that is that you’re using NSCalendarIdentifierGregorian rather than NSCalendarIdentifierISO8601. There are /lots/ of different ways to do week-of-year calculations. I can go into the gory details if you’d like, but the ‘take home’ message here is that, if you want ISO 8601 week calculations, you should use NSCalendarIdentifierISO8601.

With that change getWeek() starts producing results that match ISO 8601. Specifically:

print(self.getWeek(self.dateFromFixedFormatString("2015-12-27 12:34")))
print(self.getWeek(self.dateFromFixedFormatString("2015-12-28 12:34")))

Prints:

  • 52
  • 53

Assuming:

func dateFromFixedFormatString(dateStr: String) -> NSDate {
   let df = NSDateFormatter()
   df.locale = NSLocale(localeIdentifier: "en_US_POSIX")
   df.dateFormat = "yyyy-MM-dd HH:mm"
   return df.dateFromString(dateStr)!
}
func getWeek(today:NSDate) -> Int {
   let myCalendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierISO8601)!
   let myComponents = myCalendar.components(.WeekOfYear, fromDate: today)
   let weekNumber = myComponents.weekOfYear
   return weekNumber
}

So anyone stating the GregorianCalendar does not work in my code is correct, and should be using the NSCalendarIdentifierISO8601 specifically. NSCalendar.currentCalendar() does not automatically get the ISO calendar. (very strange)

Upvotes: 9

Tiza
Tiza

Reputation: 33

I have made your program compile with small fixes and changed the calendar to ISO. This delivers the desired result for 2015, please test with other years.

import Foundation

let now = NSDate()

func addDays(date: NSDate, amount: Int) -> NSDate {
    // calculation $additionalDays
    let additionalDays = amount
    // adding $additionalDays
    let components = NSDateComponents()
    components.day = additionalDays

    // important: NSCalendarOptions(0)
    let futureDate = NSCalendar.currentCalendar()
        .dateByAddingComponents(components, toDate: date, options: NSCalendarOptions(rawValue: 0))
    return futureDate!
}

func getWeek(today:NSDate)->Int {
    let formatter = NSDateFormatter()
    formatter.dateFormat = "yyyy-MM-dd"
    let myCalendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierISO8601)!
    let myComponents = myCalendar.components(.WeekOfYear, fromDate: today)
    let weekNumber = myComponents.weekOfYear
    return weekNumber
}

print(getWeek(addDays(now, amount: 6)))

Upvotes: 0

Tiza
Tiza

Reputation: 33

Please have in mind that ISO week and US week numbering is different! If you look up the Wikipedia article mentioned above, please read further until "Other week numbering systems". Therefore there must be a setting to control US versus ISO weeks.

Upvotes: 0

Stephen
Stephen

Reputation: 1153

This may be a bug in Apple's implementation. Apple seems to think that Dec 27, 2015 is in week 1 of 2016. However, per the ISO week date standard, it should be in week 53, as Dec 31st is on Thursday. (A Dec 31st on Wednesday should be considered Week 1: https://en.wikipedia.org/wiki/ISO_week_date#Last_week).

To get around this behavior, you may need to do some additional calculation. For example, you could check the .YearForWeekOfYear to check for a 2016 week 1 and make a determination from there.

Upvotes: 0

Related Questions