Five Weekends
October 16, 2018
This task comes to us from Rosetta Code: The month of October 2010 has five Fridays, five Saturdays and five Sundays.
Your task is to count and make a list of all months from 1900 to 2100, inclusive, that have five Fridays, Saturdays and Sundays, and to count and make a list of all years from 1900 to 2100, inclusive, that have no such months. When you are finished, you are welcome to read or run a suggested solution, or to post your own solution or discuss the exercise in the comments below.
I saw this as one of those viral posts on Facebook a few years ago, claiming that this happened only once in a few hundred years, and was ‘lucky’ according to ancient Chinese custom.
At that point I debunked it using Excel, but here’s a quick Python version. It operates on the principle that only 31 day months which start on Friday have this characteristic.
from calendar import weekday, FRIDAY from collections import defaultdict POSSIBLE_MONTHS = [1, 3, 5, 7, 8, 10, 12] def five_weekends(year, month): return weekday(year, month, 1) == FRIDAY results = defaultdict(list) number = 0 has_no_five_weekend_months = [] for year in range(1900, 2101): for month in POSSIBLE_MONTHS: if five_weekends(year, month): results[year].append(month) number += 1 if results[year] == []: has_no_five_weekend_months.append(year) print(f'{len(has_no_five_weekend_months)} years have no five-weekend months:') for year in has_no_five_weekend_months: print(f'\t{year}') print('Months with five weekends:') for year in results: if results[year] != []: print(f'\t{year}\t{results[year]}')Results:
/bin/sh is the language of choice. Find months for which /usr/bin/cal prints 31 on a line by itself.
#!/bin/sh y=1900 count=0 while [ $y -le 2100 ] do f=0 for m in 1 3 5 7 8 10 12 do if LANG=C cal $m $y | grep -q '^31' then echo $y $m f=1 count="`expr $count + 1`" fi done [ $f -eq 0 ] && echo $y none y="`expr $y + 1`" done echo $count 5-weekend monthsHere’s a solution in C.
#include <stdint.h> #include <stdio.h> #include <stdlib.h> int main(int argc, char* argv[]) { int y_start = 1900; int n_years = 201; static int candidates[] = {1, 3, 5, 7, 8, 10, 12}; static int n_candidates = sizeof(candidates) / sizeof(int); uint8_t year_months[n_years]; for (int i = 0; i < n_years; ++i) { uint8_t months = 0; for (int j = 0; j < n_candidates; ++j) { int y = y_start + i; int m = candidates[j]; int d = 1; int dow = (d+=m<3?y--:y-2,23*m/9+d+4+y/4-y/100+y/400)%7; if (dow == 5) months |= (1 << j); } year_months[i] = months; } int counter = 0; printf("*** Five Weekend Months ***\n\n"); for (int i = 0; i < n_years; ++i) { int y = y_start + i; uint8_t months = year_months[i]; if (!months) continue; for (int j = 0; j < n_candidates; ++j) { if (1 & months) { ++counter; printf("%d. %02d/%d\n", ++counter, candidates[j], y); } months >>= 1; } } counter = 0; printf("\n*** Years Missing Five Weekend Months ***\n\n"); for (int i = 0; i < n_years; ++i) { int y = y_start + i; if (!year_months[i]) { ++counter; printf("%d. %d\n", counter, y); } } return EXIT_SUCCESS; }Output: