Search code examples
sql-servert-sql

Calculate eastern easter date in SQL


I need help calculating the Eastern / Orthodox Easter. I tried searching here and all I found was the Western / Catholic Easter, not the Eastern / Orthodox Easter. I found a python snippet, and I want to convert it to T-SQL, but it gives me wrong results.

The python snippet:

y=2025
d=(y%19*19+15)%30
e=(y%4*2+y%7*4-d+34)%7+d+127
m=e/31
a=e%31+1+(m>4)
if a>30:a,m=1,5
print (a,'/',m,'/',y)

The SQL is trying to convert it to:

DECLARE @param_YEAR_NUMBER SMALLINT = 2025;

DECLARE @local_YEAR_IN_LUNAR_CYCLE TINYINT = @param_YEAR_NUMBER % 19;

DECLARE @local_YEAR_PERIOD_IN_LUNAR_CYCLE TINYINT = @local_YEAR_IN_LUNAR_CYCLE * 19;

DECLARE @local_FIX_1 TINYINT = (@local_YEAR_PERIOD_IN_LUNAR_CYCLE + 15) % 30;

DECLARE @local_FIX_2 TINYINT = ((((@param_YEAR_NUMBER % 4) *2) + ((@param_YEAR_NUMBER % 7) * 4) - @local_FIX_1 + 34) % 7) + @local_FIX_1 + 127;

DECLARE @local_EASTERN_EASTER_MONTH TINYINT = @local_FIX_2 / 31;}

DECLARE @local_EASTERN_EASTER_DAY TINYINT = (@local_FIX_1 % 31) + 1;

IF (@local_EASTERN_EASTER_MONTH > 4)
BEGIN
    SET @local_EASTERN_EASTER_DAY = @local_EASTERN_EASTER_DAY + 1;
END;
    
IF (@local_EASTERN_EASTER_DAY > 30)
BEGIN
    SET @local_EASTERN_EASTER_DAY = 1;

    SET @local_EASTERN_EASTER_MONTH = 5;
END;

With my SQL code I get April 15, instead of April 20 (Easter date for 2025). What's wrong with my code? I don't know much Python, so I have no idea what I'm doing wrong.


Solution

  • I suggest you use this formula adapted from Turanos question How to create the greek orthodox easter calendar in sql server?

    DECLARE @year SMALLINT = 2025;
        
    SELECT  CONVERT(DATE, RTRIM(@year) + '0' + RTRIM([Month]) 
                    + RIGHT('0' + RTRIM([Day]),2)) as OrthodoxEaster
    FROM (SELECT [Month], [Day] = DaysToSunday + 28 - (31 * ([Month] / 4))
    FROM (SELECT [Month] = 3 + (DaysToSunday + 40) / 44, DaysToSunday
    FROM (SELECT DaysToSunday = paschal - ((@year + @year / 4 + paschal - 13) % 7)
    FROM (SELECT paschal = epact - (epact / 28)
    FROM (SELECT epact = (24 + 19 * (@year % 19)) % 30) 
                    AS epact) AS paschal) AS dts) AS m) AS d
    

    Another solution was found and adapted from https://www.sqlservercentral.com/scripts/calculating-easter-in-sql New Scientist (30 March 1961) - Modification of the Anonymous Gregorian algorithm

    /*    
    a       y % 19                       year's position in 19-year lunar phase cycle
    b, c    y / 100, y % 100             corrections for century years
    d, e    b / 4, b % 4                 leap-year exceptions in century years
    g       8 * b + 13 / 25              century-year auxiliary corrections to the new-moon and full-moon dates
    h       (19*a + b - d - g + 15) % 30 number of days between 21 March and the coincident or next following full moon
    i, k    c / 4, c % 4                 position of the year in the ordinary leap-year cycle
    l       (32 + 2*e + 2*i - h - k) % 7 number between 0 and 6 which is one less than the number of days before the next Sunday which is definitely after the full moon
    m       (a + 11*h + 19*l) / 433          correction for transfer of full moon from a Sunday to a Saturday m = 1 for the required correction else 0
    n       (h + l - 7*m + 90) / 25          the month on the Gregorian Calendar h + l - 7*m = number of days between 21 March and Easter
    p       (h + l - 7*m + 33*n + 19) % 32)  the day of the month on the Gregorian calendar
    */
    
    DECLARE @y SMALLINT = 2025;
                
    Select * --e9.EasterDay
    From (Values (@y % 19, @y / 100, @y % 100))                       As e1(a, b, c)
    Cross Apply (Values (b / 4, b % 4))                               As e2(d, e)
    Cross Apply (Values ((8*b + 13) / 25))                            As e3(g)
    Cross Apply (Values ((19*a + b - d - g + 15) % 30, c / 4, c % 4)) As e4(h, i, k) 
    Cross Apply (Values ((32 + 2*e + 2*i - h - k) % 7))               As e5(l)
    Cross Apply (Values ((a + 11*h + 19*l) / 433))                    As e6(m)
    Cross Apply (Values ((h + l - 7*m + 90) / 25))                    As e7(n)
    Cross Apply (Values ((h + l - 7*m + 33*n + 19) % 32))             As e8(p)
    Cross Apply (Values (datefromparts(@y, n, p)))                    As e9(EasterDay)
    

    fiddle