After this year's Christmas being on a Sunday rendered my normal holiday schedule completely disrupted (ok, perhaps negligibly inconvenienced would be more fitting), I wondered what the regularity or patterns of Sunday Christmases there might be. This is what I look for in this mini-post.

In [1]:
import calendar as cal
import datetime as dt
from pandas import pandas as pd, DataFrame
pd.options.display.notebook_repr_html = False

The following few lines give the date and day of week of all the Christmases in the 21st century:

In [2]:
christmas = lambda year: dt.date(year, 12, 25)

ydf = DataFrame({'Yr': range(2000, 2100)})
ydf['Xmas'] = pd.to_datetime(ydf.Yr.map(christmas))
ydf['Xmas_dow'] = ydf.Xmas.dt.strftime('%a')
ydf[:10]
Out[2]:
     Yr       Xmas Xmas_dow
0  2000 2000-12-25      Mon
1  2001 2001-12-25      Tue
2  2002 2002-12-25      Wed
3  2003 2003-12-25      Thu
4  2004 2004-12-25      Sat
5  2005 2005-12-25      Sun
6  2006 2006-12-25      Mon
7  2007 2007-12-25      Tue
8  2008 2008-12-25      Thu
9  2009 2009-12-25      Fri

A simple rule of thumb we can see is that the day of week that Christmas falls on increases by one every year, except for leap years where it increases by 2 days.

The following block encodes something like Sunday epochs (Sun_epoch), where the count is only incremented on the years with a Christmas on a Sunday.

In [3]:
ydf['Sunday'] = ydf.Xmas_dow == 'Sun'
ydf['Sun_epoch'] = ydf.Sunday.cumsum()
ydf[:7]
Out[3]:
     Yr       Xmas Xmas_dow Sunday  Sun_epoch
0  2000 2000-12-25      Mon  False          0
1  2001 2001-12-25      Tue  False          0
2  2002 2002-12-25      Wed  False          0
3  2003 2003-12-25      Thu  False          0
4  2004 2004-12-25      Sat  False          0
5  2005 2005-12-25      Sun   True          1
6  2006 2006-12-25      Mon  False          1

This enables a quick summary of the intervals, showing a pattern where we'll typically have to wait 5 or 6 years for a Sunday, but occasionally have to wait up to 11 years:

In [4]:
ydf.query('Sun_epoch > 0').groupby('Sun_epoch').Yr.agg(['size', 'min'])
Out[4]:
           size   min
Sun_epoch            
1             6  2005
2             5  2011
3             6  2016
4            11  2022
5             6  2033
6             5  2039
7             6  2044
8            11  2050
9             6  2061
10            5  2067
11            6  2072
12           11  2078
13            6  2089
14            5  2095

It looks like 2016 began an epoch of Sunday-free Christmases that will last for 6 years, after which we'll have a dry spot of 11 years without the inconvenient Sunday Christmas.

A last thing I'm curious about is the regularity of Christmas occurring on a weekend, which is almost as undesirable for me:

In [5]:
ydf['Weekend'] = ydf.Xmas_dow.isin(['Sat', 'Sun'])
ydf['Wkd_epoch'] = ydf.Weekend.cumsum()
ydf.query('Wkd_epoch > 0').groupby('Wkd_epoch').Yr.agg(['size', 'min'])
Out[5]:
           size   min
Wkd_epoch            
1             1  2004
2             5  2005
3             1  2010
4             5  2011
5             5  2016
6             1  2021
7             5  2022
8             5  2027
9             1  2032
10            5  2033
11            1  2038
12            5  2039
13            5  2044
14            1  2049
15            5  2050
16            5  2055
17            1  2060
18            5  2061
19            1  2066
20            5  2067
21            5  2072
22            1  2077
23            5  2078
24            5  2083
25            1  2088
26            5  2089
27            1  2094
28            5  2095

As expected, these occur much more frequently, and without the periodic 11-year respite.