Developer Developer - 4 months ago 19
iOS Question

NSDateFormatter and NSDateComponents return different values for the week number

I'm making an app that creates a timetable. You can create a new one every week of the year. When the app has finished loading, it needs to load up the current week (For example: If it's the 1st of January, week 1 needs to be shown). I use NSDateFormatter to determine what the current week is.

NSDateFormatter

(I was testing this on the 9th of August 2016)

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"ww"];

int currentWeek = [[time stringFromDate:[NSDate date]] intValue];


I wanted to check if it was working so I used NSLog.

NSLog(@"%i", currentWeek);


It returned
32
.

NSDateComponents

So NSDateFormatter thinks the current week is
32
. So far, so good. The app needs to send a push notification to tell the user that a certain period is about to begin. So the app schedules a notification using NSDateComponents.

// Setting the notification's fire date.
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
NSDateComponents *dateComps = [[NSDateComponents alloc] init];
[dateComps setWeekday:3]; // Because it's on a Tuesday
[dateComps setWeekOfYear:currentWeek]; // 32
[dateComps setYear:2016];
[dateComps setHour:12];
[dateComps setMinute:20];
NSDate *theFireDate = [calendar dateFromComponents:dateComps];

// Creates the notification.
UILocalNotification *Alert = [[UILocalNotification alloc] init];
Alert.timeZone = [NSTimeZone defaultTimeZone];
Alert.alertBody = @"This is a message!";
Alert.fireDate = theFireDate;
[[UIApplication sharedApplication] scheduleLocalNotification:Alert];


And I also used NSLog.

NSLog(@"%@", theFireDate);


But it returned
2016-08-02 12:20:00 +0000
which is not the current date. It actually is the current date minus 7 days, or one week earlier. So does this mean that the current week is actually
33
instead of
32
, which means NSDateFormatter is wrong? Or is it actually
32
which means NSDateComponents is wrong. And what causes the difference between those two?

Answer

Don't use NSDateFormatter, use NSCalendar which is much more accurate.

NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
NSInteger weekOfYear = [calendar component:NSCalendarUnitWeekOfYear fromDate:[NSDate date]];