Passover
March 30, 2010
Here is our calculation of the date of Rosh Hashanah:
(define (rosh-hashanah year)
(let* ((g (+ (remainder year 19) 1))
(r (remainder (* 12 g) 19))
(n (+ (- (quotient year 100) (quotient year 400) 2)
(* 765433 r 1/492480)
(/ (remainder year 4) 4)
(- (/ (+ (* 313 year) 89081) 98496))))
(d (quotient (numerator n) (denominator n)))
(f (- n d))
(j (julian year 9 d)))
(case (modulo j 7)
((2 4 6) (+ j 1))
((0) (if (and (>= f 23269/25920) (> r 11)) (+ j 1) j))
((1) (if (and (>= f 1367/2160) (> r 6)) (+ j 2) j))
(else j))))
In the let, g is the golden number (the number of the year in the 19-year metonic cycle), n is the calculation given above, d and f are the day and fraction portions of n, respectively, and r and j are temporary variables. The calculation of the date of Passover is simple:
(define (passover year)
(let-values (((y m d) (gregorian (rosh-hashanah year))))
(let ((j (julian year 3 21)))
(if (= m 9) (+ j d) (+ j d 30)))))
For example:
> (gregorian (passover 2010))
2010
3
30
We used julian and gregorian from the Standard Prelude. You can run the program at http://programmingpraxis.codepad.org/dPbrwFze.
[…] Praxis – Passover By Remco Niemeijer In today’s Programming Praxis exercise we have to write functions to calculate the dates of the Jewish […]
My Haskell solution (see http://bonsaicode.wordpress.com/2010/03/30/programming-praxis-passover/ for a version with comments):
import Data.Time.Calendar import Data.Time.Calendar.WeekDate import Data.Fixed roshDay :: Integer -> Integer roshDay year | elem d [3,5,7] = n + 1 | d == 1 && f >= 23269/25920 && r > 11 = n + 1 | d == 2 && f >= 1367/2160 && r > 6 = n + 2 | otherwise = n where y = fromIntegral year g = mod' y 19 + 1 r = mod' (12 * g) 19 a // b = fromIntegral $ floor (a / b) (n, f) = properFraction (y // 100 - y // 400 - 2 + 765433/492480 * r + mod' y 4 / 4 - (313 * y + 89081) / 98496) (_,_,d) = toWeekDate . addDays n $ fromGregorian year 8 31 roshHashanah :: Integer -> Day roshHashanah year = addDays (roshDay year) (fromGregorian year 8 31) passover :: Integer -> Day passover year = addDays (roshDay year) (fromGregorian year 3 21)Python:
from math import floor from datetime import date, timedelta def rosh_hashanah(year): g = year % 19 + 1 r = 12*g % 19 v = ( floor( year / 100.0 ) - floor( year / 400.0 ) - 2 ) v += 765433.0 * r / 492480 v += ( year % 4 ) / 4.0 v -= ( 313.0 * year + 89081 ) / 98496 n = int(v) f = v - n # Monday .. Sunday = 0..6 dow = ( date( year, 8, 31 ).weekday() + n ) % 7 if dow in (2,4,6): n += 1 elif dow == 0 and f >= 23269.0 / 25920 and r > 11: n += 1 elif dow == 1 and f >= 1367.0 / 2160 and r > 6: n += 2 return n def passover(year): return date(year,3,21) + timedelta(rosh_hashanah(year))