2010-02-03 29 views
24

Entonces, aquí hay un pequeño desafío de programación divertido. Estaba escribiendo un método rápido para determinar todas las vacaciones de mercado para un año en particular, y luego comencé reading about Easter y descubrí lo loca que es la lógica para determinar su fecha: ¡el primer domingo después del Paschal Full Moon después del equinoccio de primavera! ¿Alguien sabe de una función existente para calcular la fecha de Pascua para un año determinado?Función para devolver la fecha de Pascua para el año dado

De acuerdo, probablemente no todo que difícil de hacer; Pensé que lo haría en caso de que alguien ya haya hecho esto. (Y eso parece muy probable.)

ACTUALIZACIÓN: En realidad, estoy realmente en busca de la fecha de Viernes Santo (viernes antes de Pascua) ... Sólo pensé Pascua me llevaría allí . Y dado que estoy en los EE. UU., ¿Supongo que estoy buscando la Pascua Católica? Pero tal vez alguien me puede corregir eso si estoy equivocado.

* Por "loco" quise decir, como, involucrado. No es nada ofensivo ...

+7

Qué Pascua? Católico, ortodoxo o copto? –

+0

¿Cuál es el primer año para el que debería funcionar correctamente? –

+0

Otro bonito artículo sobre "cálculo de Pascua": http://www.simple-talk.com/community/blogs/philfactor/archive/2009/01/18/71701.aspx. Y en T-SQL, de todas las cosas. –

Respuesta

11

en SQL Server El Domingo de Pascua se vería así, desplácese hacia abajo para Viernes Santo

CREATE FUNCTION dbo.GetEasterSunday 
(@Y INT) 
RETURNS SMALLDATETIME 
AS 
BEGIN 
    DECLARE  @EpactCalc INT, 
     @PaschalDaysCalc INT, 
     @NumOfDaysToSunday INT, 
     @EasterMonth INT, 
     @EasterDay INT 

    SET @EpactCalc = (24 + 19 * (@Y % 19)) % 30 
    SET @PaschalDaysCalc = @EpactCalc - (@EpactCalc/28) 
    SET @NumOfDaysToSunday = @PaschalDaysCalc - ( 
     (@Y + @Y/4 + @PaschalDaysCalc - 13) % 7 
    ) 

    SET @EasterMonth = 3 + (@NumOfDaysToSunday + 40)/44 

    SET @EasterDay = @NumOfDaysToSunday + 28 - ( 
     31 * (@EasterMonth/4) 
    ) 

    RETURN 
    ( 
     SELECT CONVERT 
     ( SMALLDATETIME, 
       RTRIM(@Y) 
      + RIGHT('0'+RTRIM(@EasterMonth), 2) 
      + RIGHT('0'+RTRIM(@EasterDay), 2) 
    ) 
END 
GO 

Viernes Santo es así y se utiliza la función de Pascua por encima de

CREATE FUNCTION dbo.GetGoodFriday 
( 
    @Y INT 
) 
RETURNS SMALLDATETIME 
AS 
BEGIN 
    RETURN (SELECT dbo.GetEasterSunday(@Y) - 2) 
END 
GO 

A partir de aquí: http://sqlserver2000.databases.aspfaq.com/why-should-i-consider-using-an-auxiliary-calendar-table.html

+0

Creo * que fuiste el primero en publicar el código que hace esto. Felicitaciones, mi amigo ... y gracias. –

+0

Esto solo funciona para los años 1900 - 2199. Antes de 1900 y después de 2199, se desvía del guión de cálculo de Easter de NOAA. El beneficio de este script es que es corto y agradable. Aquí está el [script de NOAA] (http://aa.usno.navy.mil/faq/docs/easter.php) Gracias por publicar esto. – LDawggie

+0

@LDawggie La desviación entre la versión simplificada en esta respuesta y la versión de NOAA comienza a partir de 1899 (3 de abril de 1899 (simple) frente a 2 de abril de 1899 (NOAA)). Pero difieren tan pronto como 2100 (27 de marzo de 2100 (simple) vs 28 de marzo de 2100 (NOAA)) Voy a publicar una respuesta con el algoritmo NOAA en algún momento más tarde hoy. – buckley

27

Python: utilizando dateutil's easter() function.

>>> from dateutil.easter import * 
>>> print easter(2010) 
2010-04-04 
>>> print easter(2011) 
2011-04-24 

Las funciones consigue, como argumento, el tipo de cálculo que les gusta:

EASTER_JULIAN = 1 
EASTER_ORTHODOX = 2 
EASTER_WESTERN = 3 

usted puede escoger el que sea relevante a los EE.UU..

La reducción de dos días a partir del resultado le daría Viernes:

>>> from datetime import timedelta 
>>> d = timedelta(days=-2) 
>>> easter(2011) 
datetime.date(2011, 4, 24) 
>>> easter(2011)+d 
datetime.date(2011, 4, 22) 

Curiosamente, alguien se la iteración de esto, y publicó los resultados en Wikipedia's article about the algorithm:

alt text

4

Cuando se trataba para mí escribir esto (predicción de tráfico en función de los días de la semana y vacaciones), Dejé de intentar escribirlo solo. Lo encontré en algún lugar de la red. El código era de dominio público, pero ...

suspiro

ver por sí mismo.

void dateOfEaster(struct tm* p) 
{ 
    int Y = p->tm_year; 
    int a = Y % 19; 
    int b = Y/100; 
    int c = Y % 100; 
    int d = b/4; 
    int e = b % 4; 
    int f = (b + 8)/25; 
    int g = (b - f + 1)/3; 
    int h = (19 * a + b - d - g + 15) % 30; 
    int i = c/4; 
    int k = c % 4; 
    int L = (32 + 2 * e + 2 * i - h - k) % 7; 
    int m = (a + 11 * h + 22 * L)/451; 
    p->tm_mon = ((h + L - 7 * m + 114)/31) - 1; 
    p->tm_mday = ((h + L - 7 * m + 114) % 31) + 1; 
    p->tm_hour = 12; 
    const time_t tmp = mktime(p); 
    *p = *localtime(&tmp); //recover yday from mon+mday 
} 

Es mejor dejar algunas preguntas sin responder.

Me siento afortunado de que todas las vacaciones en movimiento en mi país sean un desplazamiento fijo desde la fecha de Pascua.

+0

+1 Agradable. Trate de averiguar el horario de verano en mi país, tiene algunas anécdotas agradables. http://en.wikipedia.org/wiki/Israel_Summer_Time –

+1

Parece que el desarrollador que escribió esto dio j el eje. –

+1

Creo que este es realmente el algoritmo de Donald Knuth: http://www.linuxtopia.org/online_books/programming_books/python_programming/python_ch38.html –

1

La función SQL Server abajo es más general que la respuesta aceptada

la respuesta aceptada sólo es correcto para la gama (inclusive): 15/04/1900 a 2099-04-12

Utiliza el algoritmo proporcionado por el Observatorio Naval de los Estados Unidos (USNO)

http://aa.usno.navy.mil/faq/docs/easter.php

CREATE FUNCTION dbo.GetEasterSunday (@Y INT) 
RETURNS DATETIME 
AS 
    BEGIN 

     -- Source of algorithm : http://aa.usno.navy.mil/faq/docs/easter.php 

     DECLARE @c INT = @Y/100 
     DECLARE @n INT = @Y - 19 * (@Y/19) 
     DECLARE @k INT = (@c - 17)/25 
     DECLARE @i INT = @c - @c/4 - (@c - @k)/3 + 19 * @n + 15 
     SET @i = @i - 30 * (@i/30) 
     SET @i = @i - (@i/28) * (1 - (@i/28) * (29/(@i + 1)) * ((21 - @n)/11)) 
     DECLARE @j INT = @Y + @Y/4 + @i + 2 - @c + @c/4 
     SET @j = @j - 7 * (@j/7) 
     DECLARE @l INT = @i - @j 
     DECLARE @m INT = 3 + (@l + 40)/44 
     DECLARE @d INT = @l + 28 - 31 * (@m/4) 

     RETURN 
    ( 
     SELECT CONVERT 
     ( DATETIME, 
       RTRIM(@Y) 
      + RIGHT('0'+RTRIM(@m), 2) 
      + RIGHT('0'+RTRIM(@d), 2) 
    ) 
    ) 
    END 


GO 
Cuestiones relacionadas