Five Weekends

October 16, 2018

Our Standard Prelude makes this easy. We note that a month has five weekends if it is one of January, March, May, July, August, October or December and the first of the month falls on a Friday. Here are the months with five weekends from 1900 to 2100, inclusive:

> (list-of (list m y)
    (y range 1900 2101)
    (m in '(1 3 5 7 8 10 12))
    (= (modulo (julian y m 1) 7) 4))
((3 1901) (8 1902) (5 1903) (1 1904) (7 1904) (12 1905)
 (3 1907) (5 1908) (1 1909) (10 1909) (7 1910) (12 1911)
 (3 1912) (8 1913) (5 1914) (1 1915) (10 1915) (12 1916)
 (3 1918) (8 1919) (10 1920) (7 1921) (12 1922) (8 1924)
 (5 1925) (1 1926) (10 1926) (7 1927) (3 1929) (8 1930)
 (5 1931) (1 1932) (7 1932) (12 1933) (3 1935) (5 1936)
 (1 1937) (10 1937) (7 1938) (12 1939) (3 1940) (8 1941)
 (5 1942) (1 1943) (10 1943) (12 1944) (3 1946) (8 1947)
 (10 1948) (7 1949) (12 1950) (8 1952) (5 1953) (1 1954)
 (10 1954) (7 1955) (3 1957) (8 1958) (5 1959) (1 1960)
 (7 1960) (12 1961) (3 1963) (5 1964) (1 1965) (10 1965)
 (7 1966) (12 1967) (3 1968) (8 1969) (5 1970) (1 1971)
 (10 1971) (12 1972) (3 1974) (8 1975) (10 1976) (7 1977)
 (12 1978) (8 1980) (5 1981) (1 1982) (10 1982) (7 1983)
 (3 1985) (8 1986) (5 1987) (1 1988) (7 1988) (12 1989)
 (3 1991) (5 1992) (1 1993) (10 1993) (7 1994) (12 1995)
 (3 1996) (8 1997) (5 1998) (1 1999) (10 1999) (12 2000)
 (3 2002) (8 2003) (10 2004) (7 2005) (12 2006) (8 2008)
 (5 2009) (1 2010) (10 2010) (7 2011) (3 2013) (8 2014)
 (5 2015) (1 2016) (7 2016) (12 2017) (3 2019) (5 2020)
 (1 2021) (10 2021) (7 2022) (12 2023) (3 2024) (8 2025)
 (5 2026) (1 2027) (10 2027) (12 2028) (3 2030) (8 2031)
 (10 2032) (7 2033) (12 2034) (8 2036) (5 2037) (1 2038)
 (10 2038) (7 2039) (3 2041) (8 2042) (5 2043) (1 2044)
 (7 2044) (12 2045) (3 2047) (5 2048) (1 2049) (10 2049)
 (7 2050) (12 2051) (3 2052) (8 2053) (5 2054) (1 2055)
 (10 2055) (12 2056) (3 2058) (8 2059) (10 2060) (7 2061)
 (12 2062) (8 2064) (5 2065) (1 2066) (10 2066) (7 2067)
 (3 2069) (8 2070) (5 2071) (1 2072) (7 2072) (12 2073)
 (3 2075) (5 2076) (1 2077) (10 2077) (7 2078) (12 2079)
 (3 2080) (8 2081) (5 2082) (1 2083) (10 2083) (12 2084)
 (3 2086) (8 2087) (10 2088) (7 2089) (12 2090) (8 2092)
 (5 2093) (1 2094) (10 2094) (7 2095) (3 2097) (8 2098)
 (5 2099) (1 2100) (10 2100))

Counting them is easy:

> (length
    (list-of (list m y)
      (y range 1900 2101)
      (m in '(1 3 5 7 8 10 12))
      (= (modulo (julian y m 1) 7) 4)))
201

We use unique and list-minus to compute the years without a five-weekend month:

> (reverse (list-minus (range 1900 2101) (unique =
    (list-of y
      (y range 1900 2101)
      (m in '(1 3 5 7 8 10 12))
      (= (modulo (julian y m 1) 7) 4)))))
(1900 1906 1917 1923 1928 1934 1945 1951 1956 1962 1973 1979
 1984 1990 2001 2007 2012 2018 2029 2035 2040 2046 2057 2063
 2068 2074 2085 2091 2096)

And here we count them:

> (length (list-minus (range 1900 2101) (unique =
    (list-of y
      (y range 1900 2101)
      (m in '(1 3 5 7 8 10 12))
      (= (modulo (julian y m 1) 7) 4)))))
29

 

You can run the program at https://ideone.com/FTYOVo.

Advertisements

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 )

Google+ photo

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

Twitter picture

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

Facebook photo

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

Connecting to %s

%d bloggers like this: