Search code examples
iphoneobjective-cnscalendarnsdatecomponents

NextDateMatchingDay objective-c method - is there a better way than this code I've got?


NextDateMatchingDay objective-c method - is there a better way than this code I've got?

- (NSDate*)NextDateMatchingDay:(NSDateComponents*)dayTime {
    // Find next date (including date & time) from current date, for which:
    // (a) the DayOfWeek(no time) matches that dayOfWeek from the input "dateTime" NSDateComponents
    // (b) the date is > currentDateTime
    // (c) the final date time will be based on the time passed in by "dateTime" NSDateComponents
    // e.g. dayTime=Sun10am's, currentDate=Sun1st2pm => result=Sun8th10am
    // e.g. dayTime=Sun10am's, currentDate=Sun1st9am => result=Sun1st10am
    // e.g. dayTime=Sun10am's, currentDate=Fri1st1pm => result=Sun8th10am

    // Prepare
    NSDate *currDate = [NSDate date];
    NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
    NSDateComponents *addComps = [[[NSDateComponents alloc] init] autorelease];

    unsigned unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit |  NSDayCalendarUnit;
    NSDateComponents* currComps =  [gregorian components:unitFlags fromDate:currDate];

    NSInteger daysCounter = 0;
    do {
        [addComps setDay:daysCounter];
        NSDate *futureDate = [gregorian dateByAddingComponents:addComps toDate:currDate options:0];
        NSDateComponents* futureComps = [gregorian components:unitFlags fromDate:futureDate];

        if ( [futureComps day] == [currComps day] && [futureComps month] == [currComps month] && [futureComps year]  == [currComps year] )
            return futureDate;

        daysCounter++;                        
    } while (daysCounter < 10);     // just a double check 

    return nil;                     // double check - should not get to this
}

Solution

  • this seems to be an improvement - not sure if there's still a way to condense down further though?

    + (NSDate*)NextDateMatchingDay:(NSDateComponents*)dayTime sourceDate:(NSDate*)sourceDate {
        // Find next date (including date & time) from current date, for which:
        // (a) the DayOfWeek(no time) matches that dayOfWeek from the input "dateTime" NSDateComponents
        // (b) the date is > currentDateTime
        // (c) the final date time will be based on the time passed in by "dateTime" NSDateComponents
        // e.g. dayTime=Sun10am's, currentDate=Sun1st2pm => result=Sun8th10am
        // e.g. dayTime=Sun10am's, currentDate=Sun1st9am => result=Sun1st10am
        // e.g. dayTime=Sun10am's, currentDate=Fri1st1pm => result=Sun8th10am
    
        NSDate *returnDate = [sourceDate dateWithHoursMinsSecsComps:dayTime];
    
        // Check if is same day
        NSInteger configDOW = [dayTime weekday];
        NSInteger sourceDOW = [sourceDate dayOfWeek];
        if ( configDOW == sourceDOW ) {
    
            // source date is already the correct day - but is it before or after
            if ( [returnDate isBeforeThisDate:sourceDate] ) {
                // can't be source Date - so move forward 7 days
                returnDate = [returnDate dateByAddingDays:7];
                return returnDate;
            } else {
                // can be source Date (with new time)
                return returnDate;
            }
        }
    
        // source day is on another day-of-week other than the dayTime provided value
        NSInteger dayOfWeekDiff = (7 + (configDOW - sourceDOW)) % 7;
    
        returnDate = [returnDate dateByAddingDays:dayOfWeekDiff];
        return returnDate;
    }