Emacs Lisp and Memorial Day

If you think Memorial Day came early this year, you’re right. The 25th is the earliest date possible for the last Monday in May. I wondered how long it’d been since Memorial Day was this early and decided to write a quick little program to find out.

I decided to leverage the great library of calendar functions in Emacs Lisp (Elisp) written by Edward Reingold and Nachum Dershowitz. This is the same library used in these two posts last year. As I said in the first of those posts, I don’t use Emacs as an editor, but do occasionally use it as a Lisp interpreter.

Here is my first script:

 1:  #!/usr/bin/emacs --script
 2:  
 3:  (require 'calendar)
 4:  
 5:  ; Initialize.
 6:  (setq this-year 2008)
 7:  
 8:  ; Return the most recent year that Memorial Day was on the 25th.
 9:  (defun recent-early-memorial (year)
10:    (if (= 25 (extract-calendar-day (calendar-nth-named-day -1 1 5 year)))
11:      year
12:      (recent-early-memorial (- year 1))))
13:  
14:  (princ (format "%d\n" (recent-early-memorial this-year)))

The shebang (#!) line is a clever feature—introduced in version 22—that makes it dead simple to write command-line scripts in Elisp. The heart of the program is the recent-early-memorial function defined in Lines 9-12. This function starts in the given year and works backward until it finds a year in which the last Monday in May was on the 25th. The heavy lifting is done by the call to the library function calendar-nth-named-day in Line 10:

(calendar-nth-named-day -1 1 5 year)

which gets the date (as a (month day year) list) of the last (-1) Monday (1) in May (5) of the given year (year). If the day number of that date is 25, the function returns the year; if not, the year is decremented by one and the function is run again.

Running this script told me that the last time Memorial Day was this early was in 1998, eleven years ago. I then edited Line 6 to start a new search in 1997 and found that Memorial Day was on the 25th in 1992, just six years earlier. And the time before that was in 1987, five years earlier. Rather than continue this search one step at a time, I rewrote the script to give me the years of early Memorial Days going back a few centuries1:

 1:  #!/usr/bin/emacs --script
 2:  
 3:  (require 'calendar)
 4:  
 5:  ; Initialize.
 6:  (setq this-year 2009)
 7:  
 8:  ; Return the most recent year that Memorial Day was on the 25th.
 9:  (defun recent-early-memorial (year)
10:    (if (= 25 (extract-calendar-day (calendar-nth-named-day -1 1 5 year)))
11:      year
12:      (recent-early-memorial (- year 1))))
13:  
14:  ; (princ (format "%d\n" (recent-early-memorial this-year)))
15:  
16:  ; Get the years of early Memorial Days since about 1600.
17:  (setq this-year (recent-early-memorial this-year))
18:  (princ (format "%4d\n" this-year))
19:  (while (> this-year 1600)
20:    (setq next-year (recent-early-memorial (- this-year 1)))
21:    (princ (format "%4d  %2d\n" next-year (- this-year next-year)))
22:    (setq this-year next-year))

The while loop (which I’m sure will give true Lispers the vapors) prints out both the year of each early Memorial Day and the gap between succeeding early Memorial Days. Here’s the output (edited into three sets of columns to save space):

2009              1868   6          1733   6
1998  11          1863   5          1722  11
1992   6          1857   6          1716   6
1987   5          1846  11          1711   5
1981   6          1840   6          1705   6
1970  11          1835   5          1699   6
1964   6          1829   6          1693   6
1959   5          1818  11          1682  11
1953   6          1812   6          1676   6
1942  11          1807   5          1671   5
1936   6          1801   6          1665   6
1931   5          1795   6          1654  11
1925   6          1789   6          1648   6
1914  11          1778  11          1643   5
1908   6          1772   6          1637   6
1903   5          1767   5          1626  11
1896   7          1761   6          1620   6
1891   5          1750  11          1615   5
1885   6          1744   6          1609   6
1874  11          1739   5          1598  11

So eleven years is the longest time between Memorial Days on the 25th, and the pattern between early Memorial Days goes 11, 6, 5, 6, 11, 6, 5, 6, … except around century years that aren’t leap years (you do know that most century years aren’t leap years, don’t you?).

It would be fairly easy to rework the script to have it look forward to find the next early Memorial Day. It could also go through all the years to determine the frequency with which Memorial Day falls on the 25th, the 26th, the 27th, etc. In the immortal words of too many math textbooks, I leave these changes as an exercise for the reader.

Tags:


  1. Yes, I know Memorial Day started (as Decoration Day) after the Civil War and only goes back to the 1860s. And that it wasn’t on the last Monday in May until the 1960s. Don’t be so picky. Would you be happier if I called them proleptic Memorial Days?