Calculating Easter date in PostgreSQL

1

I was installing some functions in postgresql with mysqlcompact and I came up with the idea of developing a function that calculated the day of Easter so I did a search, but how do I convert this logic below to run psql postgreSQL? >

FUNCTION data_pascoa (In_ano NUMBER) RETURN DATE IS

/**************************************

        Para calcular a data da Páscoa para qualquer ano no calendário Gregoriano
        (o calendário civil no Brasil), usa-se a seguinte fórmula, com TODAS AS
        VARIÁVEIS INTEIRAS, com os resíduos das divisões ignorados.
        Usa-se A para ano, M para mês, e D para dia.
        c = a/100
        n = a - 19*(a/19)
        k = (c - 17)/25
        i = c - c/4 - (c-k)/3 +19*n + 15
        i = i - 30*(i/30)
        i = i - (i/28)*(1-(1/28)*(29/(i+1))*((21-n)/11))
        j = a + a/4 + i + 2 -c + c/4
        j = j - 7*(j/7)
        l = i - j
        m = 3 + (l+40)/44
        d = l + 28 - 31*(m/4)

        Este algoritmo é de J.-M.Oudin (1940) e impresso no
        Explanatory Supplement to the Astronomical Almanac, ed. P.K. Seidelmann (1992).

        Retirado originalmente de
        http://www.if.ufrgs.br/~kepler/fis207/pascoa.html
        e adaptado para PL/SQL por Ricardo Falter



    ********************************************************************************/


    A   INTEGER := In_ano; -- unico parametro, o ano a se obter a data da pascoa
    M   INTEGER; -- variavel para o mes
    D   INTEGER; -- variavel para o dia
    S   INTEGER; -- variavel para o seculo
    I   INTEGER; -- variavel auxiliar
    J   INTEGER; -- variavel auxiliar
    K   INTEGER; -- variavel auxiliar
    L   INTEGER; -- variavel auxiliar
    N   INTEGER; -- variavel auxiliar
BEGIN
    S      := trunc (A / 100);
    N      := A - 19 * (trunc (A / 19) );
    K      := trunc ( (S - 17) / 25);
    I      := S - trunc (S / 4) - trunc ( (S - K) / 3) + 19 * N + 15;
    I      := I - 30 * (trunc (I / 30) );
    I      := I - (trunc (I / 28) ) * (1 - (trunc (1 / 28) ) * (trunc (29 / (I + 1) ) ) * (trunc ( (21 - N) / 11) ) );
    J      := A + trunc (A / 4) + I + 2 - S + trunc (S / 4);
    J      := J - 7 * (trunc (J / 7) );
    L      := I - J;
    M      := 3 + trunc ( (L + 40) / 44);
    D      := L + 28 - 31 * (trunc (M / 4) );
RETURN (TO_DATE (lpad (D, 2, 0) || lpad (M, 2, 0) || lpad (A, 4, 0), 'DDMMYYYY') );
END;
    
asked by anonymous 05.03.2018 / 22:49

1 answer

1

Follow the Easter calculation function in Pg / SQL using the Algorithm by JM OUDIN :

CREATE OR REPLACE FUNCTION data_pascoa( ano INTEGER ) 
RETURNS DATE AS
$BODY$
DECLARE
    mes   INTEGER;
    dia   INTEGER;
    sec   INTEGER;
    I   INTEGER;
    J   INTEGER;
    K   INTEGER;
    L   INTEGER;
    N   INTEGER;
BEGIN
    sec := trunc( ano / 100 );
    N := ano - 19 * (trunc( ano / 19 ) );
    K := trunc( (sec - 17) / 25 );
    I := sec - trunc( sec / 4 ) - trunc( (sec - K) / 3) + 19 * N + 15;
    I := I - 30 * (trunc( I / 30 ) );
    I := I - ( trunc( I / 28 ) ) * (1 - ( trunc( 1 / 28 ) ) * ( trunc(29 / (I + 1) ) ) * ( trunc( (21 - N) / 11) ) );
    J := ano + trunc( ano / 4 ) + I + 2 - sec + trunc( sec / 4 );
    J := J - 7 * ( trunc( J / 7 ) );
    L := I - J;
    mes := 3 + trunc( (L + 40) / 44 );
    dia := L + 28 - 31 * ( trunc( mes / 4 ) );

    RETURN to_date( to_char( dia, '00') || to_char( mes, '00') || to_char( ano,'0000'), 'DDMMYYYY');
END;
$BODY$
LANGUAGE plpgsql; 

SQL Fiddle: link

You can also use the Carter Algorithm to calculate the Easter Sunday date for a given year, see:

--
-- FUNCAO PARA CALCULAR A DATA DO DOMINGO DE PASCOA
-- USANDO O METODO DE CARTER
--
CREATE OR REPLACE FUNCTION data_pascoa( ano INTEGER ) 
RETURNS DATE AS
$BODY$
DECLARE
    B INTEGER;
    D INTEGER;
    E INTEGER;
    Q INTEGER;
    dia INTEGER;
    mes INTEGER;
BEGIN
    IF (ano < 1900) OR (ano > 2099) THEN
        -- O Metodo de Carter soh permite calcular a data
        --da pascoa entre os anos de 1900 e 2099
        RAISE EXCEPTION 'Ano invalido!'; 
    END IF;

    B := 255 - 11 * ( ano % 19 );
    D := ( (B - 21) % 30) + 21;

    IF( D > 38 ) THEN
        D := D - 1;
    END IF;

    E := ( ano + (ano / 4) + D + 1) % 7;
    Q := D + 7 - E;

    IF( Q < 32 ) THEN
        dia := Q;
        mes := 3;
    ELSE
        dia := Q - 31;
        mes := 4;
    END IF;

    RETURN to_date( to_char( dia, '00') || to_char( mes, '00') || to_char( ano,'0000'), 'DDMMYYYY');
END;
$BODY$
LANGUAGE plpgsql; 

SQL Fiddle: link

Complete test of functions:

--
-- TESTANDO A FUNCAO COM TODAS AS DATAS ENTRE 1900 e 2099
--
SELECT
    ano,
    data_pascoa( ano )
FROM
    generate_series( 1900, 2099 ) AS ano
ORDER BY
    ano;
    
13.03.2018 / 14:39