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.

Advertisement

Pages: 1 2

3 Responses to “Five Weekends”

  1. Alex B said

    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:

    29 years have no five-weekend months:
    	1900
    	1906
    	1917
    	1923
    	1928
    	.
    	.
    	.
    	2085
    	2091
    	2096
    Months with five weekends:
    	1901	[3]
    	1902	[8]
    	1903	[5]
    	1904	[1, 7]
    	.
    	.
    	.
    	2094	[1, 10]
    	2095	[7]
    	2097	[3]
    	2098	[8]
    	2099	[5]
    	2100	[1, 10]
    
  2. kernelbob said

    /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 months
    
  3. Daniel said

    Here’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:

    *** Five Weekend Months ***
    
    1. 03/1901
    2. 08/1902
    3. 05/1903
    4. 01/1904
    5. 07/1904
    6. 12/1905
    7. 03/1907
    ...
    195. 10/2094
    196. 07/2095
    197. 03/2097
    198. 08/2098
    199. 05/2099
    200. 01/2100
    201. 10/2100
    
    *** Years Missing Five Weekend Months ***
    
    1. 1900
    2. 1906
    3. 1917
    4. 1923
    5. 1928
    6. 1934
    7. 1945
    ...
    23. 2057
    24. 2063
    25. 2068
    26. 2074
    27. 2085
    28. 2091
    29. 2096
    

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: