Version 12 of Calculating the Date of Easter

Updated 2012-02-25 21:01:04 by gkubu

A little calculator to get the date of Easter in various years using an algorithm from the Astronomy FAQ. MNO

 #!/bin/sh
 # next line restarts with tclsh \
        exec tclsh $0 ${1+"$@"}
 #
 # Author: Mark Oakden http://wiki.tcl.tk/MNO
 # Version: 1.0
 #
 # calculate Easter Sunday using the algorithm given at 
 # http://www.faqs.org/faqs/astronomy/faq/part3
 #
 # assumes Gregorian calendar
 #
 proc easterdate { year } {
     #
     # G is "golden number"
     #
     set G [expr {($year % 19) + 1}]
     #
     # H is intermediate in calculating C
     #
     set H [expr {int($year / 100)}]
     #
     # C is "century term"
     #
     set C [expr {(-1 * $H) + int($H/4) + int(8*($H+11)/25)}]
     #
     # first we need the paschal full moon.
     # the following is in days before april 19 with a couple of exceptions
     #
     set rawdays [expr {((11*$G)+$C) % 30}]
     #
     # exceptions if rawdays = 0 use days=1
     # if rawdays = 1 and G >= 12 use days=2
     # else use days=rawdays
     #
     if { $rawdays == 0 } then {
        set days 1
     } elseif { $rawdays == 1 && $G >= 12} {
        set days 2
     } else {
        set days $rawdays
     }
     #
     # now find the day that this falls on:-
     #
     set apr19 [clock scan "04/19/$year 12:00"]
     # %w is week day number Sun=0 
     set pfmweekdaynum [clock format [add_days $apr19 -$days] -format "%w"]
     #
     # Easter sunday is the next Sunday _strictly_ after PFM, so
     # if pfmweekday is sunday, we want 7 days after pfm
     # if pfmweekday is monday, we want 6 days after pfm etc.
     # i.e. we want to take (7-pfmweekdaynum) days after pfm
     #
     set easterdate [add_days $apr19 [expr {-($days - 7 + $pfmweekdaynum)}]]

     return $easterdate
 }

 proc add_days {time days} {
     if {[info tclversion] < "8.5"} {
         set res [clock scan "$days days" -base $time]
     } else {
         set res [clock add $time $days days]
     }
     return $res
 }

 for { set i 1995 } { $i <= 2015 } { incr i } {
     puts "Easter Sunday in $i will be on [clock format [easterdate $i] -format {%b %d}]"
 }

PT writes: In a strange twist of fate - the very day this was posted a colleague wished to know this date for 2004. Tcl wins the day!


TFW OK, now someone with more time on their hands than me compute the Orthodox dates. Look at http://www.assa.org.au/edm.html#OrthCalculator for a clue.


Gerald Lester Put braces around expressions just like they should be.


glennj 2008-02-08 -- removed date arithmetic using 86400 seconds per day, replaced with use of proper clock math


GWM of course this only works for the period 1902-2037 (as the clock function runs out of seconds in 32 bit). Hopefully we will all be using 64 bit by then! Any hope of calculating Easter pre-1902?

NB there is an approximately 19 year cycle for the date of Easter [L1 ] try this:

  for { set i 1906 } { $i <= 2138 } { incr i 19 } {
     puts "Easter Sunday in $i will be on [clock format [easterdate $i] -format {%b %d}]"
  }

and

  for { set i 1905 } { $i <= 2138 } { incr i 19 } {
     puts "Easter Sunday in $i will be on [clock format [easterdate $i] -format {%b %d}]"
  }

and

  for { set i 1904 } { $i <= 2138 } { incr i 19 } {
     puts "Easter Sunday in $i will be on [clock format [easterdate $i] -format {%b %d}]"
  }

to see the repetition of days within 3-4 days of each other (of course these days are rounded to the nearest Sunday). This relates to the Metonic cycle of the moons orbit [L2 ] which returns to the same position very nearly every 19 years. The effect is also seen in the dates of solar eclipses (known to the Greeks).


gkubu another algorithm (doesn't need 64 bit architecture :-)

proc gregorianEasterSunday year {

  # returns date (ISO format yyyy-mm-dd) of Easter Sunday for the given year 
  # http://www.ptb.de/cms/fachabteilungen/abt4/fb-44/ag-441/darstellung-der-gesetzlichen-zeit/wann-ist-ostern.html

    set x $year    ;# use variable names as in "wann-ist-ostern.html"

  # k: century
    set k [ expr { $x/100 } ]                           

  # auxiliary computations
    set m [ expr { 15 + (3*$k + 3)/4 - (8*$k + 13)/25 } ]     
    set s [ expr { 2 - (3*$k + 3)/4 } ]                     
    set a [ expr { $x % 19 } ]
    set d [ expr { (19*$a + $m) % 30 } ]
    set r [ expr { $d/29 + ($d/28 - $d/29) * $a/11 } ]

  # og: date of full moon in march
    set og [ expr { 21 + $d - $r } ]

  # sz: first sunday in march
    set sz [ expr { 7 - ($x + $x/4 + $s) % 7 } ]

  # oe: intermediate
  # os: Easter Sunday (number of days counted from March 1st -> 32 = April 1st)
  # om: month (march or april) of Easter
    set oe [ expr { 7 - ($og-$sz) % 7 } ]
    set os [ expr { $og + $oe } ]
    set om [ expr { 3 + $os/32 } ]

  # day in month
    if { $os > 31 } {
        set os [ expr { $os - 31 } ]
    }

    return "$x-[format %02d $om]-[format %02d $os]"

}