Search code examples
cocoacocoa-touchnsdatenscalendardate-arithmetic

Calculating the date of the first day of the week for a date in the first week of the year changes the month


I need to get date for the first day of the week from any date. This code works fine, but for some dates I get a very strange result. A date from the first week of the year converts to last week's date:

NSTimeInterval ti = 1420311299;
NSDate* date = [NSDate dateWithTimeIntervalSince1970:ti];

NSLog(@"%@", date); // OUTPUT: 2015-01-03 18:54:59 +0000

NSCalendar* calendar = [NSCalendar currentCalendar];
NSDateComponents *cmps = [calendar components:(kCFCalendarUnitWeekOfYear | kCFCalendarUnitYear) fromDate:date];

cmps.weekday = calendar.firstWeekday;

NSLog(@"%@", cmps); // OUTPUT:  Calendar Year: 2015
                    //          Week of Year: 1
                    //          Weekday: 1



NSDate* newDate = [calendar dateFromComponents:cmps];

NSLog(@"%@", newDate); // OUTPUT: 2015-12-26 22:00:00 +0000

Solution

  • The NSCalendar class offers dedicated methods to do calculations like this:

    NSDate *date =...;
    NSDate *startOfTheWeek;
    NSTimeInterval interval;
    [[NSCalendar currentCalendar] rangeOfUnit:NSCalendarUnitWeekOfMonth
                                    startDate:&startOfTheWeek 
                                     interval:&interval 
                                      forDate:date];
    

    interval contains the length of the week. If you don't need that, you can just pass in NULL.

    NSDate *date =...;
    NSDate *startOfTheWeek;
    [[NSCalendar currentCalendar] rangeOfUnit:NSCalendarUnitWeekOfMonth 
                                    startDate:&startOfTheWeek 
                                     interval:NULL
                                      forDate:date];
    

    To answer your original question: Weeks' starts and ends are not aligned with years'. The 1st, 2nd, and 3rd of January might be in the 53rd week of the previous year. 29th, 30th, 31st December might be in the 1st week of the following year. The rule is: if this week's Thursday is in December, the week belongs to the old year. If it is in January, the week is the first week of the new year.


    Every Mac/iOS Developer should watch: WWDC 2011 Video "Session 117 - Performing Calendar Calculations"