Question

I'm having some trouble computing specific days relative to the current date using NSDate and NSDateComponents. For example, let's say I want last Friday. I tried the following:

    NSDateComponents *components = [[NSCalendar currentCalendar] components:(NSYearCalendarUnit| NSMonthCalendarUnit | NSDayCalendarUnit | NSWeekCalendarUnit |  NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit | NSWeekdayCalendarUnit | NSWeekdayOrdinalCalendarUnit) fromDate:[NSDate date]];

[components setHour:0];
[components setMinute:0];
[components setSecond:0];
[components setWeekday:6]; //Friday
[components setWeek:[components week] - 1]; //Last Week

return [[NSCalendar currentCalendar] dateFromComponents:components];

But that just returns the current date, as if it can't figure out what I'm asking for.

This feels like it should be simple enough but I'm just not getting it working. Any pointers?

Was it helpful?

Solution

How about something like this:

NSDate* today = [NSDate date];
NSDateComponents* comps = [[NSCalendar currentCalendar] components:NSWeekdayCalendarUnit fromDate:today];

// do the modulo arithmetic to determine the delta days to last Friday
NSInteger weekday = [comps weekday];
NSInteger deltaDays = 0; // left as exercise, I am hungry for lunch...

NSDateComponents* delta = [[NSDateComponents alloc] init];
[delta setDay:deltaDays];
NSDate* lastFriday = [[NSCalendar currentCalendar] dateByAddingComponents:delta toDate:today options:0];

[delta release];

OTHER TIPS

Use this code:

- (NSDate *)lastDayOfMonthWithDate:(NSDate *)date
{
    NSDateComponents *components = [[NSCalendar currentCalendar] components:NSYearCalendarUnit | NSMonthCalendarUnit fromDate:date];
    components.month += 1;
    components.day = 0;

    NSDate *lastDayOfMonth = [[NSCalendar currentCalendar] dateFromComponents:components];

    return lastDayOfMonth;
}

- (NSDate *)lastFridayOfMonthWithDate:(NSDate *)date
{
    NSDateComponents *components = [[NSCalendar currentCalendar] components:NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSWeekdayCalendarUnit fromDate:[self lastDayOfMonthWithDate:date]];

    if (components.weekday >= 6) {
        components.day -= components.weekday - 6;
    } else {
        components.day +=  6 - components.weekday - 7;
    }

    NSDate *lastFridayOfMonth = [[NSCalendar currentCalendar] dateFromComponents:components];

    return lastFridayOfMonth;
}

I wrote this function:

- (NSInteger)lastOccurrenceOfWeekdayWithNumber:(NSInteger)weekdayNumber inMonthForDate:(NSDate *)date {
NSCalendarUnit units = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitWeekday | NSCalendarUnitWeekdayOrdinal;
NSRange range = [_calendar rangeOfUnit:NSCalendarUnitDay inUnit:NSCalendarUnitMonth forDate:date];
NSDateComponents *dateComponents = [_calendar components:units fromDate:date];
dateComponents.day = range.length;

date = [_calendar dateFromComponents:dateComponents];
dateComponents = [_calendar components:units fromDate:date];

while (dateComponents.weekday != weekdayNumber) {
    dateComponents.day -= 1;
    date = [_calendar dateFromComponents:dateComponents];
    dateComponents = [_calendar components:units fromDate:date];
}

return dateComponents.weekdayOrdinal;
}

weekdayNumber is 1 when you are looking for Sunday. 2 for Monday.

If you want to find last Friday in October you can use this:

[self lastOccurrenceOfWeekdayWithNumber:6 inMonthForDate:date];

where date is let's say the 11th of October, 2016 or any other day of October.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top