easter.py 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. """
  2. Copyright (c) 2003-2007 Gustavo Niemeyer <gustavo@niemeyer.net>
  3. This module offers extensions to the standard python 2.3+
  4. datetime module.
  5. """
  6. __author__ = "Gustavo Niemeyer <gustavo@niemeyer.net>"
  7. __license__ = "PSF License"
  8. import datetime
  9. __all__ = ["easter", "EASTER_JULIAN", "EASTER_ORTHODOX", "EASTER_WESTERN"]
  10. EASTER_JULIAN = 1
  11. EASTER_ORTHODOX = 2
  12. EASTER_WESTERN = 3
  13. def easter(year, method=EASTER_WESTERN):
  14. """
  15. This method was ported from the work done by GM Arts,
  16. on top of the algorithm by Claus Tondering, which was
  17. based in part on the algorithm of Ouding (1940), as
  18. quoted in "Explanatory Supplement to the Astronomical
  19. Almanac", P. Kenneth Seidelmann, editor.
  20. This algorithm implements three different easter
  21. calculation methods:
  22. 1 - Original calculation in Julian calendar, valid in
  23. dates after 326 AD
  24. 2 - Original method, with date converted to Gregorian
  25. calendar, valid in years 1583 to 4099
  26. 3 - Revised method, in Gregorian calendar, valid in
  27. years 1583 to 4099 as well
  28. These methods are represented by the constants:
  29. EASTER_JULIAN = 1
  30. EASTER_ORTHODOX = 2
  31. EASTER_WESTERN = 3
  32. The default method is method 3.
  33. More about the algorithm may be found at:
  34. http://users.chariot.net.au/~gmarts/eastalg.htm
  35. and
  36. http://www.tondering.dk/claus/calendar.html
  37. """
  38. if not (1 <= method <= 3):
  39. raise ValueError, "invalid method"
  40. # g - Golden year - 1
  41. # c - Century
  42. # h - (23 - Epact) mod 30
  43. # i - Number of days from March 21 to Paschal Full Moon
  44. # j - Weekday for PFM (0=Sunday, etc)
  45. # p - Number of days from March 21 to Sunday on or before PFM
  46. # (-6 to 28 methods 1 & 3, to 56 for method 2)
  47. # e - Extra days to add for method 2 (converting Julian
  48. # date to Gregorian date)
  49. y = year
  50. g = y % 19
  51. e = 0
  52. if method < 3:
  53. # Old method
  54. i = (19*g+15)%30
  55. j = (y+y//4+i)%7
  56. if method == 2:
  57. # Extra dates to convert Julian to Gregorian date
  58. e = 10
  59. if y > 1600:
  60. e = e+y//100-16-(y//100-16)//4
  61. else:
  62. # New method
  63. c = y//100
  64. h = (c-c//4-(8*c+13)//25+19*g+15)%30
  65. i = h-(h//28)*(1-(h//28)*(29//(h+1))*((21-g)//11))
  66. j = (y+y//4+i+2-c+c//4)%7
  67. # p can be from -6 to 56 corresponding to dates 22 March to 23 May
  68. # (later dates apply to method 2, although 23 May never actually occurs)
  69. p = i-j+e
  70. d = 1+(p+27+(p+6)//40)%31
  71. m = 3+(p+26)//30
  72. return datetime.date(int(y),int(m),int(d))