We host a holiday party for our friends and neighbors on the Sunday after Christmas, unless that is New Year's Eve, then our party is on Saturday, a day earlier.
I have trouble remembering these simple rules. I thought it would help if I programmed them. I chose CoffeeScript.
My challenge was to write them such that they were clearly without error.
I start with a series of functions that find useful days given some other day to work from.
christmasDay = (day) -> new Date day.getFullYear(), 11, 25 followingSunday = (day) -> daysToSunday = 7 - day.getDay() new Date day.getFullYear(), day.getMonth(), day.getDate() + daysToSunday dayBefore = (day) -> new Date day.getFullYear(), day.getMonth(), day.getDate() - 1 beforeNewYearsEve = (day) -> if day.getDate() == 31 dayBefore day else day
I depend on normalized dates: e.g. December 32 becomes January 1 the following year.
I depend on months and day of week starting with zero, but year and day of month from one.
The party date is computed by applying these functions one after another, working forward from Christmas and backwards from New Year's Eve.
holidayParty = (day) -> beforeNewYearsEve followingSunday christmasDay day
Surprisingly I must have made twenty or thirty mistakes writing this simple logic. I found them by running a number of years. I checked both Saturday and Sunday appeared, that no 31 appeared, that every year appeared (but it won't), and sometimes printed intermediate values just to understand what has gone wrong.
for year in [1995..2025] console.log holidayParty new Date(year, 0, 1)
These are the answers I finally accepted as correct.
Sat Dec 30 1995 00:00:00 GMT-0800 (PST) Sun Dec 29 1996 00:00:00 GMT-0800 (PST) Sun Dec 28 1997 00:00:00 GMT-0800 (PST) Sun Dec 27 1998 00:00:00 GMT-0800 (PST) Sun Dec 26 1999 00:00:00 GMT-0800 (PST) Sat Dec 30 2000 00:00:00 GMT-0800 (PST) Sun Dec 30 2001 00:00:00 GMT-0800 (PST) Sun Dec 29 2002 00:00:00 GMT-0800 (PST) Sun Dec 28 2003 00:00:00 GMT-0800 (PST) Sun Dec 26 2004 00:00:00 GMT-0800 (PST) Sun Jan 01 2006 00:00:00 GMT-0800 (PST) Sat Dec 30 2006 00:00:00 GMT-0800 (PST) Sun Dec 30 2007 00:00:00 GMT-0800 (PST) Sun Dec 28 2008 00:00:00 GMT-0800 (PST) Sun Dec 27 2009 00:00:00 GMT-0800 (PST) Sun Dec 26 2010 00:00:00 GMT-0800 (PST) Sun Jan 01 2012 00:00:00 GMT-0800 (PST) Sun Dec 30 2012 00:00:00 GMT-0800 (PST) Sun Dec 29 2013 00:00:00 GMT-0800 (PST) Sun Dec 28 2014 00:00:00 GMT-0800 (PST) Sun Dec 27 2015 00:00:00 GMT-0800 (PST) Sun Jan 01 2017 00:00:00 GMT-0800 (PST) Sat Dec 30 2017 00:00:00 GMT-0800 (PST) Sun Dec 30 2018 00:00:00 GMT-0800 (PST) Sun Dec 29 2019 00:00:00 GMT-0800 (PST) Sun Dec 27 2020 00:00:00 GMT-0800 (PST) Sun Dec 26 2021 00:00:00 GMT-0800 (PST) Sun Jan 01 2023 00:00:00 GMT-0800 (PST) Sat Dec 30 2023 00:00:00 GMT-0800 (PST) Sun Dec 29 2024 00:00:00 GMT-0800 (PST) Sun Dec 28 2025 00:00:00 GMT-0800 (PST)