Search code examples
iosobjective-ccocoa-touchnsdatedate-arithmetic

Count weeks between dates and present that as an NSString like Instagram


I have some NSDates that I want to present in terms of weeks, like what Instagram does with their photos timestamp. Values would be "This week", "Last week", "2 weeks ago", and so on to "N weeks ago".

Please help me figure out this algorithm.


Solution

  • Any date arithmetic you need to do in Cocoa (Touch) will involve NSCalendar and NSDateComponents. They can figure out for you how the differences between two dates quite easily.

    NSDate * originDate = ...;
    NSCalendar * cal = [NSCalendar currentCalendar];
    NSDateComponents * weekComp = [cal components:NSCalendarUnitWeekOfYear
                                         fromDate:originDate
                                           toDate:[NSDate date] // right now
                                          options:0];
    

    Now [weekComp weekOfYear] will tell you how many weeks are in between those two dates.

    From there, it's just some string formatting:

    NSInteger weeksAgo = [weekComp weekOfYear];
    NSString * timestampString;
    switch( weeksAgo ){
        case 0:
            timestampString = @"This week";
            break;
        case 1:
            timestampString = @"Last week";
            break;
        default:
            timestampString = [NSString stringWithFormat:@"%d weeks ago", (int)weeksAgo];
    }
    

    If you need to count by "calendar" weeks (Sunday through Saturday), so that on Wednesday the previous Saturday is "last week", you'll have to take into account the weekdays of the dates.

    NSDateComponents * weekdayComp = [cal components:NSCalendarUnitWeekday|NSCalendarUnitWeekOfYear
                                            fromDate:originDate
                                              toDate:objDate
                                             options:0];
    NSInteger weekdaysAgo = [weekdayComp weekday];
    NSInteger objWeekday = [cal component:NSCalendarUnitWeekday fromDate:objDate];
        
    

    Asking the calendar for these two deltas -- weekday and week of year -- in the same call will result in e.g., "1 week, 2 days" for the interval Mon, Jul 13, 2015 to Wed, Jul 22, 2015; the larger unit will be calculated first, and the smaller will be filled with the remainder.

    Then you get the weekday number (Sunday=1, Monday=2, etc.) for the target date. If the weekdaysAgo value is equal or greater, the origin date is in the week previous to that indicated by the weakOfYear value. Floored division will give the number of weeks to add (either 1 or 0).

    NSInteger weeksAgo = [weekdayComp weekOfYear] + (weekdaysAgo / objWeekday);
    

    Then, use this new weeksAgo value with the same switch from above.