Question

I'm looking for a way to calculate the number of Tuesdays in the current month in Objective C.

For example if the code ran today (July 16, 2012) it would ouput 5 because there are 5 Tuesdays in the month of July in 2012 (the 3rd, 10th, 17th, 24th, and 31st).

I have seen solutions online for doing it in Excel, but I am struggling translating it to Objective C.

Thanks for your help! Long time, first time.

Was it helpful?

Solution

We're going to need a calendar:

    NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];

Now let's get the current month and year:

    NSDate *now = [NSDate date];
    NSDateComponents *monthAndYear = [calendar components:NSMonthCalendarUnit | NSYearCalendarUnit fromDate:now];

We can use that to get the first Tuesday of the current month and year:

    NSDateComponents *firstTuesdayComponents = [monthAndYear copy];
    firstTuesdayComponents.weekday = 3; // Sunday = 1
    firstTuesdayComponents.weekdayOrdinal = 1; // First Tuesday
    NSDate *firstTuesday = [calendar dateFromComponents:firstTuesdayComponents];

We can also use it to get the first day of next month:

    NSDateComponents *firstOfNextMonthComponents = [monthAndYear copy];
    firstOfNextMonthComponents.month += 1;
    firstOfNextMonthComponents.day = 1;
    NSDate *firstOfNextMonth = [calendar dateFromComponents:firstOfNextMonthComponents];

Now we can ask for the number of days between the two dates:

    NSDateComponents *differenceComponents = [calendar components:NSDayCalendarUnit fromDate:firstTuesday toDate:firstOfNextMonth options:0];

Most weeks have seven days and a single Tuesday, so we should divide the number of days by 7. If there's a remainder, we should round it up because we started counting from a Tuesday.

    int tuesdayCount = (differenceComponents.day + 6) / 7; // Adding 6 makes the integer division round up.
    NSLog(@"There are %d Tuesdays in month %d of year %d.", tuesdayCount, (int)monthAndYear.month, (int)monthAndYear.year);

Now let's hop in the time machine to test it:

There are 5 Tuesdays in month 1 of year 2012.
There are 4 Tuesdays in month 2 of year 2012.
There are 4 Tuesdays in month 3 of year 2012.
There are 4 Tuesdays in month 4 of year 2012.
There are 5 Tuesdays in month 5 of year 2012.
There are 4 Tuesdays in month 6 of year 2012.
There are 5 Tuesdays in month 7 of year 2012.
There are 4 Tuesdays in month 8 of year 2012.
There are 4 Tuesdays in month 9 of year 2012.
There are 5 Tuesdays in month 10 of year 2012.
There are 4 Tuesdays in month 11 of year 2012.
There are 4 Tuesdays in month 12 of year 2012.

OTHER TIPS

When looking at the outputs of cal 2012, cal 2011, and cal 2000, I've drawn a few conclusions:

There are either four or five Tuesdays in every month.

To find the months with five Tuesdays, note:

  • For months with 31 days, the first must fall on a Sunday, Monday, or Tuesday
  • For months with 30 days, the first must fall on a Monday or Tuesday
  • For months with 29 days, the first must fall on a Tuesday

Hopefully this is an easier problem to solve.

Using an algorithm based on the same observation sarnold made in his answer, this should do the trick:

- (NSUInteger)numberOfTuesdaysInMonthContainingDate:(NSDate *)date
{
    NSCalendar *calendar = [NSCalendar currentCalendar];

    NSUInteger numDaysInMonth = [calendar rangeOfUnit:NSDayCalendarUnit inUnit:NSMonthCalendarUnit forDate:date].length;

    NSDate *firstDayOfMonth;
    NSTimeInterval firstDayOfMonthLength;
    if (![calendar rangeOfUnit:NSMonthCalendarUnit startDate:&firstDayOfMonth interval:&firstDayOfMonthLength forDate:date]) {
        NSLog(@"Unable to calculate first day of the month for %@", date);
        return 0;
    }

    NSUInteger firstDayOfTheMonthWeekday = [calendar ordinalityOfUnit:NSWeekdayCalendarUnit inUnit:NSWeekCalendarUnit forDate:firstDayOfMonth];

    // The following is for Tuesday only, the math is more complex for an abitrary weekday
    NSUInteger numTuesdays = 4;
    NSUInteger minValidWeekday = 32 - numDaysInMonth; 
    if (firstDayOfTheMonthWeekday >= minValidWeekday && firstDayOfTheMonthWeekday <= 3) {
        numTuesdays = 5;
    }

    return numTuesdays;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top