Number of Tuesdays in the current month in objective c
-
21-06-2021 - |
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.
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;
}