【问题标题】:Function to return date of Easter for the given year返回给定年份复活节日期的函数
【发布时间】:2011-01-12 15:32:06
【问题描述】:

所以,这是一个有趣的小编程挑战。我正在编写一个快速方法来确定特定年份的所有市场假期,然后我开始reading about Easter 并发现确定其日期的逻辑是多么疯狂* - 春季之后Paschal Full Moon 之后的第一个星期日春分!有人知道计算给定年份复活节日期的现有函数吗?

当然,这可能并不是所有那么都很难做到;我只是想我会问,以防有人已经这样做了。 (这似乎很有可能。)

更新:实际上,我真的在寻找耶稣受难日(复活节前的星期五)的日期...我只是以为复活节会把我带到那里。既然我在美国,我想我正在寻找天主教复活节?但如果我错了,也许有人可以纠正我。

*我所说的“疯狂”是指,参与。没有任何冒犯...

【问题讨论】:

  • 哪个复活节?天主教、东正教还是科普特?
  • 它应该在哪一年正常工作?
  • 另一个关于“计算复活节”的好文章:simple-talk.com/community/blogs/philfactor/archive/2009/01/18/…。在 T-SQL 中,最重要的是。
  • @AJ:哈,好问题。当然是公元某年... ;)
  • “有许多迹象表明,中世纪欧洲算术的唯一重要应用是计算复活节的日期。” – 克努斯

标签: datetime language-agnostic calendar computus


【解决方案1】:

Python:使用dateutil's easter() function

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

函数获取您喜欢的计算类型作为参数:

EASTER_JULIAN   = 1
EASTER_ORTHODOX = 2
EASTER_WESTERN  = 3

您可以选择与美国相关的。

从结果中减少两天将给你耶稣受难日:

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

奇怪的是,有人在迭代这个,并将结果发布在Wikipedia's article about the algorithm

【讨论】:

    【解决方案2】:

    在 SQL Server 中,复活节星期日看起来像这样,向下滚动查看耶稣受难日

    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
    

    耶稣受难日是这样的,它使用了上面的复活节功能

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

    从这里:http://web.archive.org/web/20070611150639/http://sqlserver2000.databases.aspfaq.com/why-should-i-consider-using-an-auxiliary-calendar-table.html

    【讨论】:

    • 这仅适用于 1900 - 2199 年。1900 年之前和 2199 年之后,它偏离了 NOAA 的复活节计算脚本。这个脚本的好处是它短小精悍。这是NOAA's script 感谢您发布此信息。
    • @LDawggie 此答案中的简化版本与 NOAA 版本之间的偏差确实始于 1899 年(1899 年 4 月 3 日(简单)与 1899 年 4 月 2 日(NOAA))。但它们会在 2100 年(2100 年 3 月 27 日(简单)与 2100 年 3 月 28 日(NOAA))有所不同。我将在今天晚些时候发布使用 NOAA 算法的答案。
    【解决方案3】:

    当我写这篇文章时(基于星期几和节假日的交通预测), 我放弃了自己写的尝试。我在网上的某个地方找到了它。该代码是公共领域的,但是...

    叹息

    自己看看。

    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
    }
    

    有些问题最好不要问。

    我很幸运,我国家的所有搬家假期都是从复活节日期开始的固定偏移量。

    【讨论】:

    【解决方案4】:

    下面的 SQL Server 函数比公认的答案更通用

    接受的答案仅适用于范围(包括):1900-04-15 到 2099-04-12

    它使用美国海军天文台 (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
    

    【讨论】:

      【解决方案5】:

      以下代码通过powershell判断复活节:

      function Get-DateOfEaster {
          param(
              [Parameter(ValueFromPipeline)]
              $theYear=(Get-Date).Year
              )
      
          if($theYear -lt 1583) {
              return $null
          } else {
      
              # Step 1: Divide the theYear by 19 and store the
              # remainder in variable A.  Example: If the theYear
              # is 2000, then A is initialized to 5.
      
              $a = $theYear % 19
      
              # Step 2: Divide the theYear by 100.  Store the integer
              # result in B and the remainder in C.
      
              $c = $theYear % 100
              $b = ($theYear -$c) / 100
      
              # Step 3: Divide B (calculated above).  Store the
              # integer result in D and the remainder in E.
      
              $e = $b % 4
              $d = ($b - $e) / 4
      
              # Step 4: Divide (b+8)/25 and store the integer
              # portion of the result in F.
      
              $f = [math]::floor(($b + 8) / 25)
      
              # Step 5: Divide (b-f+1)/3 and store the integer
              # portion of the result in G.
      
              $g = [math]::floor(($b - $f + 1) / 3)
      
              # Step 6: Divide (19a+b-d-g+15)/30 and store the
              # remainder of the result in H.
      
              $h = (19 * $a + $b - $d - $g + 15) % 30
      
              # Step 7: Divide C by 4.  Store the integer result
              # in I and the remainder in K.
      
              $k = $c % 4
              $i = ($c - $k) / 4
      
              # Step 8: Divide (32+2e+2i-h-k) by 7.  Store the
              # remainder of the result in L.
      
              $l = (32 + 2 * $e + 2 * $i - $h - $k) % 7
      
              # Step 9: Divide (a + 11h + 22l) by 451 and
              # store the integer portion of the result in M.
      
              $m = [math]::floor(($a + 11 * $h + 22 * $l) / 451)
      
              # Step 10: Divide (h + l - 7m + 114) by 31.  Store
              # the integer portion of the result in N and the
              # remainder in P.
      
              $p = ($h + $l - 7 * $m + 114) % 31
              $n = (($h + $l - 7 * $m + 114) - $p) / 31
      
              # At this point p+1 is the day on which Easter falls.
              # n is 3 for March and 4 for April.
      
              $DateTime = New-Object DateTime $theyear, $n, ($p+1), 0, 0, 0, ([DateTimeKind]::Utc)
              return $DateTime
          }
      }
      
      $eastersunday=Get-DateOfEaster 2015
      Write-Host $eastersunday
      

      【讨论】:

        【解决方案6】:

        用于希腊东正教和天主教复活节的 VB .NET 函数:

        Public Shared Function OrthodoxEaster(ByVal Year As Integer) As Date
            Dim a = Year Mod 19
            Dim b = Year Mod 7
            Dim c = Year Mod 4
            Dim d = (19 * a + 16) Mod 30
            Dim e = (2 * c + 4 * b + 6 * d) Mod 7
            Dim f = (19 * a + 16) Mod 30
            Dim key = f + e + 3
            Dim month = If((key > 30), 5, 4)
            Dim day = If((key > 30), key - 30, key)
            Return New DateTime(Year, month, day)
        End Function
        
        Public Shared Function CatholicEaster(ByVal Year As Integer) As DateTime
            Dim month = 3
            Dim a = Year Mod 19 + 1
            Dim b = Year / 100 + 1
            Dim c = (3 * b) / 4 - 12
            Dim d = (8 * b + 5) / 25 - 5
            Dim e = (5 * Year) / 4 - c - 10
            Dim f = (11 * a + 20 + d - c) Mod 30
            If f = 24 Then f += 1
            If (f = 25) AndAlso (a > 11) Then f += 1
            Dim g = 44 - f
            If g < 21 Then g = g + 30
            Dim day = (g + 7) - ((e + g) Mod 7)
            If day > 31 Then
                day = day - 31
                month = 4
            End If
            Return New DateTime(Year, month, day)
        End Function
        

        【讨论】:

          【解决方案7】:

          在某处发现了这个 Excel 公式
          假设单元格A1 包含年份,例如2020

          ROUND(DATE(A1;4;1)/7+MOD(19*MOD(A1;19)-7;30)*0,14;0)*7-6
          

          转换为 T-SQL 导致我这样做:

          DECLARE @yr INT=2020
          SELECT DATEADD(dd, ROUND(DATEDIFF(dd, '1899-12-30', DATEFROMPARTS(@yr, 4, 1)) / 7.0 + ((19.0 * (@yr % 19) - 7) % 30) * 0.14, 0) * 7.0 - 6, -2)
          

          【讨论】:

            【解决方案8】:

            在 JS 中,取自 here

            var epoch=2444238.5,elonge=278.83354,elongp=282.596403,eccent=.016718,sunsmax=149598500,sunangsiz=.533128,mmlong=64.975464,mmlongp=349.383063,mlnode=151.950429,minc=5.145396,mecc=.0549,mangsiz=.5181,msmax=384401,mparallax=.9507,synmonth=29.53058868,lunatbase=2423436,earthrad=6378.16,PI=3.141592653589793,epsilon=1e-6;function sgn(x){return x<0?-1:x>0?1:0}function abs(x){return x<0?-x:x}function fixAngle(a){return a-360*Math.floor(a/360)}function toRad(d){return d*(PI/180)}function toDeg(d){return d*(180/PI)}function dsin(x){return Math.sin(toRad(x))}function dcos(x){return Math.cos(toRad(x))}function toJulianTime(date){var year,month,day;year=date.getFullYear();var m=(month=date.getMonth()+1)>2?month:month+12,y=month>2?year:year-1,d=(day=date.getDate())+date.getHours()/24+date.getMinutes()/1440+(date.getSeconds()+date.getMilliseconds()/1e3)/86400,b=isJulianDate(year,month,day)?0:2-y/100+y/100/4;return Math.floor(365.25*(y+4716)+Math.floor(30.6001*(m+1))+d+b-1524.5)}function isJulianDate(year,month,day){if(year<1582)return!0;if(year>1582)return!1;if(month<10)return!0;if(month>10)return!1;if(day<5)return!0;if(day>14)return!1;throw"Any date in the range 10/5/1582 to 10/14/1582 is invalid!"}function jyear(td,yy,mm,dd){var z,f,alpha,b,c,d,e;return f=(td+=.5)-(z=Math.floor(td)),b=(z<2299161?z:z+1+(alpha=Math.floor((z-1867216.25)/36524.25))-Math.floor(alpha/4))+1524,c=Math.floor((b-122.1)/365.25),d=Math.floor(365.25*c),e=Math.floor((b-d)/30.6001),{day:Math.floor(b-d-Math.floor(30.6001*e)+f),month:Math.floor(e<14?e-1:e-13),year:Math.floor(mm>2?c-4716:c-4715)}}function jhms(j){var ij;return j+=.5,ij=Math.floor(86400*(j-Math.floor(j))+.5),{hour:Math.floor(ij/3600),minute:Math.floor(ij/60%60),second:Math.floor(ij%60)}}function jwday(j){return Math.floor(j+1.5)%7}function meanphase(sdate,k){var t,t2;return 2415020.75933+synmonth*k+1178e-7*(t2=(t=(sdate-2415020)/36525)*t)-155e-9*(t2*t)+33e-5*dsin(166.56+132.87*t-.009173*t2)}function truephase(k,phase){var t,t2,t3,pt,m,mprime,f,apcor=!1;if(pt=2415020.75933+synmonth*(k+=phase)+1178e-7*(t2=(t=k/1236.85)*t)-155e-9*(t3=t2*t)+33e-5*dsin(166.56+132.87*t-.009173*t2),m=359.2242+29.10535608*k-333e-7*t2-347e-8*t3,mprime=306.0253+385.81691806*k+.0107306*t2+1236e-8*t3,f=21.2964+390.67050646*k-.0016528*t2-239e-8*t3,phase<.01||abs(phase-.5)<.01?(pt+=(.1734-393e-6*t)*dsin(m)+.0021*dsin(2*m)-.4068*dsin(mprime)+.0161*dsin(2*mprime)-4e-4*dsin(3*mprime)+.0104*dsin(2*f)-.0051*dsin(m+mprime)-.0074*dsin(m-mprime)+4e-4*dsin(2*f+m)-4e-4*dsin(2*f-m)-6e-4*dsin(2*f+mprime)+.001*dsin(2*f-mprime)+5e-4*dsin(m+2*mprime),apcor=!0):(abs(phase-.25)<.01||abs(phase-.75)<.01)&&(pt+=(.1721-4e-4*t)*dsin(m)+.0021*dsin(2*m)-.628*dsin(mprime)+.0089*dsin(2*mprime)-4e-4*dsin(3*mprime)+.0079*dsin(2*f)-.0119*dsin(m+mprime)-.0047*dsin(m-mprime)+3e-4*dsin(2*f+m)-4e-4*dsin(2*f-m)-6e-4*dsin(2*f+mprime)+.0021*dsin(2*f-mprime)+3e-4*dsin(m+2*mprime)+4e-4*dsin(m-2*mprime)-3e-4*dsin(2*m+mprime),pt+=phase<.5?.0028-4e-4*dcos(m)+3e-4*dcos(mprime):4e-4*dcos(m)-.0028-3e-4*dcos(mprime),apcor=!0),!apcor)throw"Error calculating moon phase!";return pt}function phasehunt(sdate,phases){var adate,k1,k2,nt1,nt2,yy,mm,dd,jyearResult=jyear(adate=sdate-45,yy,mm,dd);for(yy=jyearResult.year,mm=jyearResult.month,dd=jyearResult.day,adate=nt1=meanphase(adate,k1=Math.floor(12.3685*(yy+1/12*(mm-1)-1900)));nt2=meanphase(adate+=synmonth,k2=k1+1),!(nt1<=sdate&&nt2>sdate);)nt1=nt2,k1=k2;return phases[0]=truephase(k1,0),phases[1]=truephase(k1,.25),phases[2]=truephase(k1,.5),phases[3]=truephase(k1,.75),phases[4]=truephase(k2,0),phases}function kepler(m,ecc){var e,delta;e=m=toRad(m);do{e-=(delta=e-ecc*Math.sin(e)-m)/(1-ecc*Math.cos(e))}while(abs(delta)>epsilon);return e}function getMoonPhase(julianDate){var Day,N,M,Ec,Lambdasun,ml,MM,MN,Ev,Ae,MmP,mEc,lP,lPP,NP,y,x,MoonAge,MoonPhase,MoonDist,MoonDFrac,MoonAng,F,SunDist,SunAng;return N=fixAngle(360/365.2422*(Day=julianDate-epoch)),Ec=kepler(M=fixAngle(N+elonge-elongp),eccent),Ec=Math.sqrt((1+eccent)/(1-eccent))*Math.tan(Ec/2),Lambdasun=fixAngle((Ec=2*toDeg(Math.atan(Ec)))+elongp),F=(1+eccent*Math.cos(toRad(Ec)))/(1-eccent*eccent),SunDist=sunsmax/F,SunAng=F*sunangsiz,ml=fixAngle(13.1763966*Day+mmlong),MM=fixAngle(ml-.1114041*Day-mmlongp),MN=fixAngle(mlnode-.0529539*Day),MmP=MM+(Ev=1.2739*Math.sin(toRad(2*(ml-Lambdasun)-MM)))-(Ae=.1858*Math.sin(toRad(M)))-.37*Math.sin(toRad(M)),lPP=(lP=ml+Ev+(mEc=6.2886*Math.sin(toRad(MmP)))-Ae+.214*Math.sin(toRad(2*MmP)))+.6583*Math.sin(toRad(2*(lP-Lambdasun))),NP=MN-.16*Math.sin(toRad(M)),y=Math.sin(toRad(lPP-NP))*Math.cos(toRad(minc)),x=Math.cos(toRad(lPP-NP)),toDeg(Math.atan2(y,x)),NP,toDeg(Math.asin(Math.sin(toRad(lPP-NP))*Math.sin(toRad(minc)))),MoonAge=lPP-Lambdasun,MoonPhase=(1-Math.cos(toRad(MoonAge)))/2,MoonDist=msmax*(1-mecc*mecc)/(1+mecc*Math.cos(toRad(MmP+mEc))),MoonAng=mangsiz/(MoonDFrac=MoonDist/msmax),mparallax/MoonDFrac,{moonIllumination:MoonPhase,moonAgeInDays:synmonth*(fixAngle(MoonAge)/360),distanceInKm:MoonDist,angularDiameterInDeg:MoonAng,distanceToSun:SunDist,sunAngularDiameter:SunAng,moonPhase:fixAngle(MoonAge)/360}}function getMoonInfo(date){return null==date?{moonPhase:0,moonIllumination:0,moonAgeInDays:0,distanceInKm:0,angularDiameterInDeg:0,distanceToSun:0,sunAngularDiameter:0}:getMoonPhase(toJulianTime(date))}function getEaster(year){var previousMoonInfo,moonInfo,fullMoon=new Date(year,2,21),gettingDarker=void 0;do{previousMoonInfo=getMoonInfo(fullMoon),fullMoon.setDate(fullMoon.getDate()+1),moonInfo=getMoonInfo(fullMoon),void 0===gettingDarker?gettingDarker=moonInfo.moonIllumination<previousMoonInfo.moonIllumination:gettingDarker&&moonInfo.moonIllumination>previousMoonInfo.moonIllumination&&(gettingDarker=!1)}while(gettingDarker&&moonInfo.moonIllumination<previousMoonInfo.moonIllumination||!gettingDarker&&moonInfo.moonIllumination>previousMoonInfo.moonIllumination);for(fullMoon.setDate(fullMoon.getDate()-1);0!==fullMoon.getDay();)fullMoon.setDate(fullMoon.getDate()+1);return fullMoon}
            

            然后运行getEaster(2020); // -&gt; Sun Apr 12 2020

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2016-09-02
              • 1970-01-01
              • 2021-05-02
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2013-02-27
              相关资源
              最近更新 更多