codekingpro/portable-devtools
115k
1# -*- coding: utf-8 -*-2"""3This module offers a generic Easter computing method for any given year, using4Western, Orthodox or Julian algorithms.5"""6 7import datetime8 9__all__ = ["easter", "EASTER_JULIAN", "EASTER_ORTHODOX", "EASTER_WESTERN"]10 11EASTER_JULIAN = 112EASTER_ORTHODOX = 213EASTER_WESTERN = 314 15 16def easter(year, method=EASTER_WESTERN):17 """18 This method was ported from the work done by GM Arts,19 on top of the algorithm by Claus Tondering, which was20 based in part on the algorithm of Ouding (1940), as21 quoted in "Explanatory Supplement to the Astronomical22 Almanac", P. Kenneth Seidelmann, editor.23 24 This algorithm implements three different Easter25 calculation methods:26 27 1. Original calculation in Julian calendar, valid in28 dates after 326 AD29 2. Original method, with date converted to Gregorian30 calendar, valid in years 1583 to 409931 3. Revised method, in Gregorian calendar, valid in32 years 1583 to 4099 as well33 34 These methods are represented by the constants:35 36 * ``EASTER_JULIAN = 1``37 * ``EASTER_ORTHODOX = 2``38 * ``EASTER_WESTERN = 3``39 40 The default method is method 3.41 42 More about the algorithm may be found at:43 44 `GM Arts: Easter Algorithms <http://www.gmarts.org/index.php?go=415>`_45 46 and47 48 `The Calendar FAQ: Easter <https://www.tondering.dk/claus/cal/easter.php>`_49 50 """51 52 if not (1 <= method <= 3):53 raise ValueError("invalid method")54 55 # g - Golden year - 156 # c - Century57 # h - (23 - Epact) mod 3058 # i - Number of days from March 21 to Paschal Full Moon59 # j - Weekday for PFM (0=Sunday, etc)60 # p - Number of days from March 21 to Sunday on or before PFM61 # (-6 to 28 methods 1 & 3, to 56 for method 2)62 # e - Extra days to add for method 2 (converting Julian63 # date to Gregorian date)64 65 y = year66 g = y % 1967 e = 068 if method < 3:69 # Old method70 i = (19*g + 15) % 3071 j = (y + y//4 + i) % 772 if method == 2:73 # Extra dates to convert Julian to Gregorian date74 e = 1075 if y > 1600:76 e = e + y//100 - 16 - (y//100 - 16)//477 else:78 # New method79 c = y//10080 h = (c - c//4 - (8*c + 13)//25 + 19*g + 15) % 3081 i = h - (h//28)*(1 - (h//28)*(29//(h + 1))*((21 - g)//11))82 j = (y + y//4 + i + 2 - c + c//4) % 783 84 # p can be from -6 to 56 corresponding to dates 22 March to 23 May85 # (later dates apply to method 2, although 23 May never actually occurs)86 p = i - j + e87 d = 1 + (p + 27 + (p + 6)//40) % 3188 m = 3 + (p + 26)//3089 return datetime.date(int(y), int(m), int(d))90 