The problem
Recently, I had a fun problem to solve:
Given a date without year (but a range of possible years – or at least some suspicion) plus the information that this given date was a sunday, can you (easily) determine the year?
Of course, this problem can be expanded to “any weekday” – but *that* problem can be reduced to the “sunday”-one by just moving the date a bit.
Basically, this boils down to “some years are the same in terms of weekday-allocation”. As a simple example: In 1999, there was some advice “if your “device does not support year 2000, set it to yet $otherYearNumber! This way, all weekdays will match”. Our podcast-crew once observed that there are only 14 different “kinds of years”: One for each weekday to start with, multiplied by two because each of these seven sets exists in a “has february 29th”- and a “does not have february 29th”-variant. Going by modern terminology, we called those “premium”- and “plus”-years.
The code
The initial approach was to just get a lot of calendars and look it up, there. I actually did this for the “strong suspicion”-special-case – but I wanted some solution that didn’t require 30 open windows with PDF-viewers. The next approach were some trial-and-error-experiments right in the spreadsheet. Then I remembered, that I’m a software-developer.
Obviously, with the wonders of the modern java-time-package (“modern” as in “since Java 8, released 2014”), functional programming (“modern” as in “rooted in Alonzo Church’s lambda calculus from the 1930s”) and languages to easily glue this together (I used Kotlin, here), this can be programmed in very few lines of code:
fun weekdayCheck(pivotDate: MonthDay, pivotWeekDay: DayOfWeek) {
val periodBetweenDates = Period.ofYears(
if(pivotDate == MonthDay.of(Month.FEBRUARY, 29)) 4 else 1
)
val allDays = generateSequence(
pivotDate.atYear(1972),
{it.plus(periodBetweenDates)}
)
.takeWhile{it.year <= 2025}
val allMatchingWeekdayDays = allDays.filter{it.dayOfWeek == pivotWeekDay}
allMatchingWeekdayDays.forEach { println(it) }
}
The limitation to “between 1972 and 2025” is arbitry (partially due to my use-case, partially due to leap-day-support)
The lookup-tables
Toying around with this, a simple table can be constructed (dates are sundays)
| 1978 1984 1989 1995 2006 2012 2017 2023 | 1972 1977 1983 1994 2000 2005 2011 2022 | 1982 1988 1993 1999 2010 2016 2021 | 1976 1981 1987 1998 2004 2009 2015 | 1975 1986 1992 1997 2003 2014 2020 2025 | 1974 1980 1985 1991 2002 2008 2013 2019 | 1973 1979 1990 1996 2001 2007 2018 2024 |
| 01-01 01-08 01-15 01-22 01-29 | 01-02 01-09 01-16 01-23 01-30 | 01-03 01-10 01-17 01-24 01-31 | 01-04 01-11 01-18 01-25 — | 01-05 01-12 01-19 01-26 — | 01-06 01-13 01-20 01-27 — | 01-07 01-14 01-21 01-28 — |
| — 02-05 02-12 02-19 02-26 | — 02-06 02-13 02-20 02-27 | — 02-07 02-14 02-21 02-28 | 02-01 02-08 02-15 02-22 02-29 | 02-02 02-09 02-16 02-23 — | 02-03 02-10 02-17 02-24 — | 02-04 02-11 02-18 02-25 — |
| Jan-01 Jan-08 Jan-15 Jan-22 Jan-29 | Jan-02 Jan-09 Jan-16 Jan-23 Jan-30 | Jan-03 Jan-10 Jan-17 Jan-24 Jan-31 | Jan-04 Jan-11 Jan-18 Jan-25 — | Jan-05 Jan-12 Jan-19 Jan-26 — | Jan-06 Jan-13 Jan-20 Jan-27 — | Jan-07 Jan-14 Jan-21 Jan-28 — |
| — Feb-05 Feb-12 Feb-19 Feb-26 | — Feb-06 Feb-13 Feb-20 Feb-27 | — Feb-07 Feb-14 Feb-21 Feb-28 | Feb-01 Feb-08 Feb-15 Feb-22 Feb-29 | Feb-02 Feb-09 Feb-16 Feb-23 — | Feb-03 Feb-10 Feb-17 Feb-24 — | Feb-04 Feb-11 Feb-18 Feb-25 — |
Because of that pesky Leapyear-difference, I restarted the table at march
| 1981 1987 1992 1998 2009 2015 2020 | 1975 1980 1986 1997 2003 2008 2014 2025 | 1974 1985 1991 1996 2002 2013 2019 2024 | 1973 1979 1984 1990 2001 2007 2012 2018 | 1972 1978 1989 1995 2000 2006 2017 2023 | 1977 1983 1988 1994 2005 2011 2016 2022 | 1976 1982 1993 1999 2004 2010 2021 |
| 03-01 03-08 03-15 03-22 03-29 | 03-02 03-09 03-16 03-23 03-30 | 03-03 03-10 03-17 03-24 03-31 | 03-04 03-11 03-18 03-25 — | 03-05 03-12 03-19 03-26 — | 03-06 03-13 03-20 03-27 — | 03-07 03-14 03-21 03-08 — |
| — 04-05 04-12 04-19 04-26 | — 04-06 04-13 04-20 04-27 | — 04-07 04-14 04-21 04-28 | 04-01 04-08 04-15 04-22 04-29 | 04-02 04-09 04-16 04-23 04-30 | 04-03 04-10 04-17 04-24 — | 04-04 04-11 04-18 04-25 — |
| — 05-03 05-10 05-17 05-24 05-31 | — 05-04 05-11 05-18 05-25 — | — 05-05 05-12 05-19 05-26 — | — 05-06 05-13 05-20 05-27 — | — 05-07 05-14 05-21 05-28 — | 05-01 05-08 05-15 05-22 05-29 — | 05-02 05-09 05-16 05-23 05-30 — |
| — 06-07 06-14 06-21 06-28 | 06-01 06-08 06-15 06-22 06-29 | 06-02 06-09 06-16 06-23 06-30 | 06-03 06-10 06-17 06-24 — | 06-04 06-11 06-18 06-25 — | 06-05 06-12 06-19 06-26 — | 06-06 06-13 06-20 06-27 — |
| — 07-05 07-12 07-19 07-26 | — 07-06 07-13 07-20 07-27 | — 07-07 07-14 07-21 07-28 | 07-01 07-08 07-15 07-22 07-29 | 07-02 07-09 07-16 07-23 07-30 | 07-03 07-10 07-17 07-24 07-31 | 07-04 07-11 07-18 07-25 — |
| — 08-02 08-09 08-16 08-23 08-30 | — 08-03 08-10 08-17 08-24 08-31 | — 08-04 08-11 08-18 08-25 — | — 08-05 08-12 08-19 08-26 — | — 08-06 08-13 08-20 08-27 — | — 08-07 08-14 08-21 08-28 — | 08-01 08-08 08-15 08-22 08-29 — |
| — 09-06 09-13 09-20 09-27 | — 09-07 09-14 09-21 09-28 | 09-01 09-08 09-15 09-22 09-29 | 09-02 09-09 09-16 09-23 09-30 | 09-03 09-10 09-17 09-24 — | 09-04 09-11 09-18 09-25 — | 09-05 09-12 09-19 09-26 — |
| — 10-04 10-11 10-18 10-25 | — 10-05 10-12 10-19 10-26 | — 10-06 10-13 10-20 10-27 | — 10-07 10-14 10-21 10-28 | 10-01 10-08 10-15 10-22 10-29 | 10-02 10-09 10-16 10-23 10-30 | 10-03 10-10 10-17 10-24 10-31 |
| 11-01 11-08 11-15 11-22 11-29 | 11-02 11-09 11-16 11-23 11-30 | 11-03 11-10 11-17 11-24 — | 11-04 11-11 11-18 11-25 — | 11-05 11-12 11-19 11-26 — | 11-06 11-13 11-20 11-27 — | 11-07 11-14 11-21 11-28 — |
| — 12-06 12-13 12-20 12-27 | — 12-07 12-14 12-21 12-28 | 12-01 12-08 12-15 12-22 12-29 | 12-02 12-09 12-16 12-23 12-30 | 12-03 12-10 12-17 12-24 12-31 | 12-04 12-11 12-18 12-25 — | 12-05 12-12 12-19 12-26 — |
| Mar-01 Mar-08 Mar-15 Mar-22 Mar-29 | Mar-02 Mar-09 Mar-16 Mar-23 Mar-30 | Mar-03 Mar-10 Mar-17 Mar-24 Mar-31 | Mar-04 Mar-11 Mar-18 Mar-25 — | Mar-05 Mar-12 Mar-19 Mar-26 — | Mar-06 Mar-13 Mar-20 Mar-27 — | Mar-07 Mar-14 Mar-21 Mar-28 — |
| — Apr-05 Apr-12 Apr-19 Apr-26 | — Apr-06 Apr-13 Apr-20 Apr-27 | — Apr-07 Apr-14 Apr-21 Apr-28 | Apr-01 Apr-08 Apr-15 Apr-22 Apr-29 | Apr-02 Apr-09 Apr-16 Apr-23 Apr-30 | Apr-03 Apr-10 Apr-17 Apr-24 — | Apr-04 Apr-11 Apr-18 Apr-25 — |
| — May-03 May-10 May-17 May-24 May-31 | — May-04 May-11 May-18 May-25 — | — May-05 May-12 May-19 May-26 — | — May-06 May-13 May-20 May-27 — | — May-07 May-14 May-21 May-28 — | May-01 May-08 May-15 May-22 May-29 — | May-02 May-09 May-16 May-23 May-30 — |
| — Jun-07 Jun-14 Jun-21 Jun-28 | Jun-01 Jun-08 Jun-15 Jun-22 Jun-29 | Jun-02 Jun-09 Jun-16 Jun-23 Jun-30 | Jun-03 Jun-10 Jun-17 Jun-24 — | Jun-04 Jun-11 Jun-18 Jun-25 — | Jun-05 Jun-12 Jun-19 Jun-26 — | Jun-06 Jun-13 Jun-20 Jun-27 — |
| — Jul-05 Jul-12 Jul-19 Jul-26 | — Jul-06 Jul-13 Jul-20 Jul-27 | — Jul-07 Jul-14 Jul-21 Jul-28 | Jul-01 Jul-08 Jul-15 Jul-22 Jul-29 | Jul-02 Jul-09 Jul-16 Jul-23 Jul-30 | Jul-03 Jul-10 Jul-17 Jul-24 Jul-31 | Jul-04 Jul-11 Jul-18 Jul-25 — |
| — Aug-02 Aug-09 Aug-16 Aug-23 Aug-30 | — Aug-03 Aug-10 Aug-17 Aug-24 Aug-31 | — Aug-04 Aug-11 Aug-18 Aug-25 — | — Aug-05 Aug-12 Aug-19 Aug-26 — | — Aug-06 Aug-13 Aug-20 Aug-27 — | — Aug-07 Aug-14 Aug-21 Aug-28 — | Aug-01 Aug-08 Aug-15 Aug-22 Aug-29 — |
| — Sep-06 Sep-13 Sep-20 Sep-27 | — Sep-07 Sep-14 Sep-21 Sep-28 | Sep-01 Sep-08 Sep-15 Sep-22 Sep-29 | Sep-02 Sep-09 Sep-16 Sep-23 Sep-30 | Sep-03 Sep-10 Sep-17 Sep-24 — | Sep-04 Sep-11 Sep-18 Sep-25 — | Sep-05 Sep-12 Sep-19 Sep-26 — |
| — Oct-04 Oct-11 Oct-18 Oct-25 | — Oct-05 Oct-12 Oct-19 Oct-26 | — Oct-06 Oct-13 Oct-20 Oct-27 | — Oct-07 Oct-14 Oct-21 Oct-28 | Oct-01 Oct-08 Oct-15 Oct-22 Oct-29 | Oct-02 Oct-09 Oct-16 Oct-23 Oct-30 | Oct-03 Oct-10 Oct-17 Oct-24 Oct-31 |
| Nov-01 Nov-08 Nov-15 Nov-22 Nov-29 | Nov-02 Nov-09 Nov-16 Nov-23 Nov-30 | Nov-03 Nov-10 Nov-17 Nov-24 — | Nov-04 Nov-11 Nov-18 Nov-25 — | Nov-05 Nov-12 Nov-19 Nov-26 — | Nov-06 Nov-13 Nov-20 Nov-27 — | Nov-07 Nov-14 Nov-21 Nov-28 — |
| — Dec-06 Dec-13 Dec-20 Dec-27 | — Dec-07 Dec-14 Dec-21 Dec-28 | Dec-01 Dec-08 Dec-15 Dec-22 Dec-29 | Dec-02 Dec-09 Dec-16 Dec-23 Dec-30 | Dec-03 Dec-10 Dec-17 Dec-24 Dec-31 | Dec-04 Dec-11 Dec-18 Dec-25 — | Dec-05 Dec-12 Dec-19 Dec-26 — |
Leap days / Leap years
When I first did the calculation, I only looked at the timespan between 1973 and 1999 – and was “surprised” that only one leap day was a sunday. After some thinking, I realised that this actually was *above* average: with seven possible weekdays and ~4.1237 years between leap years, the “chance” of having a leap sunday is ~1/28,866; When looking at only 27 years, I was “lucky” to get even one.
But that means that there must have been weekdays that never got a leap day in that time frame. Toying around some more yielded the following info:
| Sunday | Monday | Tuesday | Wednesday | Thursday | Friday | Saturday |
| 1976 2004 | 1988 2016 | 1972 2000 | 1984 2012 | 1986 2024 | 1980 2008 | 1992 2020 |
So that confirms it: in the initial timeframe, the odd one out was Tuesday. This table also shows that outside of the pesky 100-year-rule (with the 400-year-rule-exception), the pattern repeats every 28 years.
The year-groups
To conclude things, the following “types of years” can be extracted from that info:
| cool name | Starts with | First sunday | Leap day is | Examples |
| “Sunday-Premium” | Sunday | 01-01 Jan-01 | — | 1978, 1989, 1995, 2006, 2017, 2023 |
| “Sunday-Plus” | Sunday | 01-01 Jan-01 | Wednesday | 1984, 2012 |
| “Monday-Premium” | Monday | 01-07 Jan-07 | — | 1973, 1979, 1990, 2001, 2007, 2018 |
| “Monday-Premium” | Monday | 01-07 Jan-07 | Thursday | 1996, 2024 |
| “Tuesday-Premium” | Tuesday | 01-06 Jan-06 | — | 1974, 1985, 1991, 2002, 2013, 2019 |
| “Tuesday-Plus” | Tuesday | 01-06 Jan-06 | Friday | 1980, 2008 |
| “Wednesday-Premium” | Wednesday | 01-05 Jan-05 | — | 1975, 1986, 1997, 2003, 2014, 2025 |
| “Wednesday-Plus” | Wednesday | 01-05 Jan-05 | Saturday | 1992, 2020 |
| “Thursday-Premium” | Thursday | 01-04 Jan-04 | — | 1981, 1987, 1998, 2009, 2015 |
| “Thursday-Plus” | Thursday | 01-04 Jan-04 | Sunday | 1976, 2004 |
| “Friday-Premium” | Friday | 01-03 Jan-03 | — | 1982, 1993, 1999, 2010, 2021 |
| “Friday-Plus” | Friday | 01-03 Jan-03 | Monday | 1988, 2016 |
| “Saturday-Premium” | Saturday | 01-02 Jan-02 | — | 1977, 1983, 1994, 2005, 2011, 2022 |
| “Saturday-Plus” | Saturday | 01-02 Jan-02 | Tuesday | 1972, 2000 |
You can also see that the years in each “premium”-group are six years apart – unless there is a leap-year between then… in that case, the next year in that group is 11 years away. Thankfully, 2000 was a leap year – this analysis could have easily become more complicated if “100-year-but-not-400-year-rule”-year was involved.
























































