Calculate the date of Easter

Your function or program should take a year as input and return (or print) the date (in the Gregorian calendar) of that years Easter (not the Eastern Orthodox Easter). The date returned should be formatted according to ISO 8601, but with support for years greater than 9999 (such as 312013-04-05 or 20010130), and it only needs to work with years greater than or equal to 1583 (the year of the adoption of the Gregorian calendar), and years less than or equal to 5701583 (as that is when the sequence of Easter dates starts to repeat itself).

Examples:

e(5701583) = 5701583-04-10
e(2013)    = 2013-03-31
e(1583)    = 1583-04-10
e(3029)    = 30290322
e(1789)    = 17890412
e(1725)    = 17250401


The use of built-in functions for returning the date of easter is boring and therefore disallowed. Shortest answer (in characters) wins.

Resources:

• Do you realise that some languages have a built-in function to do this? – Peter Taylor Apr 5 '13 at 13:58
• Such as? The only one I am aware of is PHP, but the easter_date and easter_days functions are quite limited, easter_date only works for years after 1970 and easter_days doesn't return the correct amount of days for years prior to 1753. But I will edit the question to disallow the use of such functions. – Fors Apr 5 '13 at 14:06
• – John Dvorak Apr 5 '13 at 14:32
• So this is Gregorian and NOT Julian? Also, I'm not Catholic, what is the "Catholic Tradition?" – jdstankosky Apr 5 '13 at 16:20
• More functions – SeanC Apr 9 '13 at 13:41

GolfScript (85 chars)

~:^100/.)3*4/.@8*13+25/-^19%.19*15+@+30%.@11/+29/23--.@-^.4/++7%97--^0@.31/100*\31%)+


Sample usage:

$golfscript.rb codegolf11132.gs <<<2013 20130331  Note that this uses a different algorithm to most of the current answers. To be specific, I've adapted the algorithm attributed to Lichtenberg in the resource linked by Sean Cheshire in a comment on the question. The original algorithm, assuming sensible types (i.e. not JavaScript's numbers) and with an adaptation to give month*31+day (using day offset of 0) is K = Y/100 M = 15 + (3*K+3)/4 - (8*K+13)/25 S = 2 - (3*K+3)/4 A = Y%19 D = (19*A+M) % 30 R = (D + A/11)/29 OG = 21 + D - R SZ = 7 - (Y + Y/4 + S) % 7 OE = 7 - (OG-SZ) % 7 return OG + OE + 92  I extracted a common subexpression and did some other optimisations to reduce to K = y/100 k = (3*K+3)/4 A = y%19 D = (19*A+15+k-(8*K+13)/25)%30 G = 23+D-(D+A/11)/29 return 97+G-(G+y+y/4-k)%7  This approach has slightly more arithmetic operations than the other one (Al Petrofsky's 20-op algorithm), but it has smaller constants; GolfScript doesn't need to worry about the extra parentheses because it's stack-based, and since each intermediate value in my optimised layout is used precisely twice it fits nicely with GolfScript's limitation of easy access to the top three items on the stack. • It has a small issue, when the date of Easter lies between the 1st of april and the 10th of april, it returns dates such as 1725041, when it should return 17250401. But upvoted for the different approach! – Fors Apr 11 '13 at 5:32 • @Fors, oops. Now fixed. – Peter Taylor Apr 11 '13 at 7:05 Python 2 - 125120 119 chars This is Fors's answer shamelessly ported to Python. y=input() a=y/100*1483-y/400*2225+2613 b=(y%19*3510+a/25*319)/330%29 b=148-b-(y*5/4+a-b)%7 print(y*100+b/31)*100+b%31+1  Edit: Changed last line from print"%d-0%d-%02d"%(y,b/31,b%31+1) to save 5 characters. I would have loved to represent 10000 as 1e4, but that would produce floating point necessitating a call to int. Edit2: Thanks to Peter Taylor for showing how to get rid of that 10000 and save 1 character. • If you split 10000up to 100*100 you can put the last line into Horner's form as (y*100+b/31)*100+b%31+1. The leading parenthesis allows you to remove the space after print, and you can pull out the three instances of 100 to a variable for an overall saving of 1 char. – Peter Taylor Apr 9 '13 at 14:34 • @PeterTaylor: Excellent suggestion. Updated my answer. – Steven Rumbalski Apr 9 '13 at 14:50 • You can make it a function e(y) and save a few bytes – sagiksp Feb 2 '17 at 8:28 PHP 154 150 chars if I switch to YYYYMMDD instead of YYYY-MM-DD. <?$y=$argv;$a=$y/100|0;$b=$a>>2;$c=($y%19*351-~($b+$a*29.32+13.54)*31.9)/33%29|0;$d=56-$c-~($a-$b+$c-24-$y/.8)%7;echo$d>31?"$y-04-".($d-31):"$y-03-$d";


With Line Breaks:

<?
$y =$argv;
$a =$y / 100 |0;
$b =$a >> 2;
$c = ($y % 19 * 351 - ~($b +$a * 29.32 + 13.54) * 31.9) / 33 % 29 |0;
$d = 56 -$c - ~($a -$b + $c - 24 -$y / .8) % 7;
echo $d > 31 ? "$y-04-".($d - 31) : "$y-03-$d";  Useage: php easter.php 1997 Output: 1997-03-30 Useage: php easter.php 2001 Output: 2001-04-15 • Great algorithm golfing, not so great code golfing. I took the freedom to chop off 18 bytes: <?=$y=$argv,"-0",3+$m=($d=56-($c=($y%19*351-~(($a=$y/100|0)*29.32+($b=$a>>2)+13.54)*31.9)/33%29)-~($a-$b+$c-24-$y/.8)%7)>>5,31*$m-\$d; – Titus Feb 2 '17 at 6:13
• Fails to meet output format. The leading zero for the day is missing where needed. E.g. for year 1725 it outputs 1725-04-1 instead of 1725-04-01. – Christoph Feb 2 '17 at 10:47

dc: 106 characters

?[0n]smdndsy100/1483*ly400/2225*-2613+dsa25/319*ly19%3510*+330/29%sb148lb-5ly*4/la+lb-7%-d31/0nn31%1+d9>mp


Usage:

> dc -e "?[0n]smdndsy100/1483*ly400/2225*-2613+dsa25/319*ly19%3510*+330/29%sb148lb-5ly*4/la+lb-7%-d31/0nn31%1+d9>mp"
1725
17250401
>


This should be able to be shortened by using 'd' and 'r' instead of all the loads and stores.

C: 151 148 characters

y;a;b;main(){scanf("%d",&y);a=y/100*1483-y/400*2225+2613;b=(y%19*3510+a/25*319)/330%29;b=148-b-(y*5/4+a-b)%7;printf("%d-0%d-%02d\n",y,b/31,b%31+1);}


And the same code, but better formatted:

#include <stdio.h>

int y, a, b;

int main() {
scanf("%d", &y);

a = y/100*1483 - y/400*2225 + 2613;
b = (y%19*3510 + a/25*319)/330%29;
b = 148 - b - (y*5/4 + a - b)%7;

printf("%d-0%d-%02d\n", y, b/31, b%31 + 1);
}


There are frightfully many algorithms for calculating the date of Easter, but only a few of them are well suited for code golfing.

Javascript 162156 145

function e(y){alert(y+"0"+((d=56-(c=(y%19*351-~((b=(a=y/100|0)>>2)+a*29.32+13.54)*31.9)/33%29|0)-~(a-b+c-24-y/.8)%7)>(f=31)?4:3)+(d-f>0&d-f<10?0:"")+(d>f?d-f:d))}


Inspired by @jdstankosky's PHP solution... Provides YYYYMMDD result...

Now narrowed down to:

alert((y=prompt())+0+((d=56-(c=(y%19*351-~((b=(a=y/100|0)>>2)+a*29.32+13.54)*31.9)/33%29|0)-~(a-b+c-24-y/.8)%7)>(f=31)?4:3)+(d-f>0&d-f<10?0:"")+(d>f?d-f:d))


Now asks for input... reduced literal string of "0" to 0 and let loose typing work to my advantage! :)

Reduced further to take ES6 into account...

e=y=>y+"0"+((d=56-(c=(y%19*351-31.9*~((b=(a=y/100|0)>>2)+29.32*a+13.54))/33%29|0)-~(a-b+c-24-y/.8)%7)>(f=31)?4:3)+(d-f>0&d-f<10?0:"")+(d>f?d-f:d)

APL 132

This algorithm calculates the number of days Easter lies relative to the beginning of March. The date is returned in the YYYYMMDD format as allowed in the question:

E y
(a b)←⌊((3 8×⌊y÷100)+¯5 13)÷4 25
c←7|y+(⌊y÷4)-a-e←⌊d-((19×d←30|(227-(11×c)-a-b))+c←19|y)÷543
+/(10*4 2 0)×y,(3+i>31),(61⍴⍳31)[i←e+28-c]


Taking the original test cases:

      E 2013
20130331
E 1583
15830410
E 3029
30290322
E 1789
17890412


Fortran (GFortran), 179 bytes

READ*,I
J=I/100*2967-I/400*8875+7961
K=MOD(MOD(I,19)*6060+(MOD(MOD(J/25,59),30)+23)*319-1,9570)/330
L=K+28-MOD(I*5/4+J+K,7)
WRITE(*,'(I7,I0.2,I0.2)')I,(L-1)/31+3,MOD(L-1,31)+1
END


Try it online!

Uses the "Emended Gregorian Easter" algorithm (Al Petrofsky) from the second resource link. Strangely, it fails for year 5701583 (and, apparently, only for this year), predicting the Easter as one week earlier. Prints the date in YYYYYYYMMDD format, with some leading spaces if the year has less then seven digits.