16
\$\begingroup\$

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:

asked Apr 5, 2013 at 13:29
\$\endgroup\$
13
  • \$\begingroup\$ Do you realise that some languages have a built-in function to do this? \$\endgroup\$ Commented Apr 5, 2013 at 13:58
  • \$\begingroup\$ 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. \$\endgroup\$ Commented Apr 5, 2013 at 14:06
  • 1
    \$\begingroup\$ resource: en.wikipedia.org/wiki/Computus#Algorithms \$\endgroup\$ Commented Apr 5, 2013 at 14:32
  • 1
    \$\begingroup\$ So this is Gregorian and NOT Julian? Also, I'm not Catholic, what is the "Catholic Tradition?" \$\endgroup\$ Commented Apr 5, 2013 at 16:20
  • 2
    \$\begingroup\$ More functions \$\endgroup\$ Commented Apr 9, 2013 at 13:41

12 Answers 12

7
\$\begingroup\$

GolfScript (85 chars)

~:^100/.)3*4/.@8*13+25/-^19%.19*15+@+30%.@11/+29/23--.@-^.4/++7%97--^[email protected]/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.

answered Apr 10, 2013 at 22:43
\$\endgroup\$
2
  • \$\begingroup\$ 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! \$\endgroup\$ Commented Apr 11, 2013 at 5:32
  • \$\begingroup\$ @Fors, oops. Now fixed. \$\endgroup\$ Commented Apr 11, 2013 at 7:05
5
\$\begingroup\$

Python 2 - (削除) 125 (削除ここまで) (削除) 120 (削除ここまで) 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.

answered Apr 8, 2013 at 18:21
\$\endgroup\$
3
  • 1
    \$\begingroup\$ 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. \$\endgroup\$ Commented Apr 9, 2013 at 14:34
  • \$\begingroup\$ @PeterTaylor: Excellent suggestion. Updated my answer. \$\endgroup\$ Commented Apr 9, 2013 at 14:50
  • \$\begingroup\$ You can make it a function e(y) and save a few bytes \$\endgroup\$ Commented Feb 2, 2017 at 8:28
4
\$\begingroup\$

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.

answered Apr 7, 2013 at 14:18
\$\endgroup\$
0
4
\$\begingroup\$

PHP 154

150 chars if I switch to YYYYMMDD instead of YYYY-MM-DD.

<?$y=$argv[1];$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[1];
$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日

answered Apr 5, 2013 at 17:25
\$\endgroup\$
2
  • 1
    \$\begingroup\$ Great algorithm golfing, not so great code golfing. I took the freedom to chop off 18 bytes: <?=$y=$argv[1],"-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; \$\endgroup\$ Commented Feb 2, 2017 at 6:13
  • \$\begingroup\$ 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日. \$\endgroup\$ Commented Feb 2, 2017 at 10:47
4
\$\begingroup\$

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.

answered Apr 8, 2013 at 19:49
\$\endgroup\$
4
\$\begingroup\$

Javascript (削除) 162 (削除ここまで) (削除) 156 (削除ここまで) 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)

answered Dec 5, 2013 at 12:04
\$\endgroup\$
3
\$\begingroup\$

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 ×ばつ⌊y÷100)+ ̄5 13)÷4 25 
c←7|y+(⌊y÷4)-a-e←⌊d-((×ばつd←30|(227-(×ばつ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 
answered Apr 8, 2013 at 10:06
\$\endgroup\$
2
\$\begingroup\$

C#, (削除) 212 (削除ここまで) 210 bytes

int y=int.Parse(args[0]),a=y%19,b=y/100,h=(19*a+b-b/4-(8*b+13)/25+15)%30,l=(32+2*(b%4)+2*(y%100/4)-h-(y%100%4))%7,m=(a+11*h+19*l)/433,n=(h+l-7*m+90)/25;Console.WriteLine($"{y}{n:D2}{(h+l-7*m+33*n+19)%32:D2}");

Try it on JDoodle

Ungolfed:

int y = int.Parse(args[0]),
 a = y % 19,
 b = y / 100,
 h = (19 * a + b - b / 4 - (8 * b + 13) / 25 + 15) % 30,
 l = (32 + 2 * (b % 4) + 2 * (y % 100 / 4) - h - (y % 100 % 4)) % 7, m = (a + 11 * h + 19 * l) / 433, n = (h + l - 7 * m + 90) / 25;
Console.WriteLine($"{y}{n:D2}{(h + l - 7 * m + 33 * n + 19) % 32:D2}");

First statement declares and calculates most variables. Second statement calculates the day, formats and prints the result. It uses the 1961 New Scientist algorithm from Wikipedia.

Edit: -2 bytes thanks for @Themoonisacheese

answered Apr 17 at 8:15
\$\endgroup\$
2
  • \$\begingroup\$ you can save 2 bytes by removing the - characters in your formatting, since they aren't required. maybe this even allows you to forgo some {}s but i'm unsure if that's true. \$\endgroup\$ Commented Apr 17 at 8:38
  • \$\begingroup\$ @Themoonisacheese Great point! I'll amend. \$\endgroup\$ Commented Apr 17 at 8:46
1
\$\begingroup\$

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.

answered Mar 29, 2018 at 22:08
\$\endgroup\$
1
\$\begingroup\$

Javascript 134 Characters

Using a slightly modified Al Petrofsky's 20-op algorithm to allow a simpler conversion into the year-month-date format.

This provides additional 14 characters shorter code from the answer provided by WallyWest

The Original Al Petrofsky's Code:

 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;

Last line changed to:

d =148-c-~(a-b+c-24-Y/.8)%7;

1. 138 Characters With the format YYYY-MM-DD

e=y=>(c=(y%19*351-31.9*~((b=(a=y/100|0)>>2)+29.32*a+13.54))/33%29|0,d=148-c-~(a-b+c-24-y/.8)%7,y+'-0'+(d/31|0)+"-"+((o=d%31+1)>9?o:'0'+o))
console.log(e(2021));
console.log(e(2022));
console.log(e(5701583));
console.log(e(2013));
console.log(e(1583));
console.log(e(3029));
console.log(e(1789));
console.log(e(1725));

2. 134 Characters With the format YYYYMMDD

e=y=>(c=(y%19*351-31.9*~((b=(a=y/100|0)>>2)+29.32*a+13.54))/33%29|0,d=148-c-~(a-b+c-24-y/.8)%7,y+'0'+(d/31|0)+((d=d%31+1)>9?d:'0'+d))
console.log(e(2021));
console.log(e(2022));
console.log(e(5701583));
console.log(e(2013));
console.log(e(1583));
console.log(e(3029));
console.log(e(1789));
console.log(e(1725));

answered Feb 16, 2021 at 16:52
\$\endgroup\$
1
\$\begingroup\$

APL(NARS), 147 chars

{{(m n o)←{2≤≢⍵:⍵⋄'0',⍵} ̈⍕ ̈⍵⋄m,'-',n,'-',o}⍵,(⌊r÷31),1+31∣r←148-r+7∣(×ばつ5÷4)+a-r←29∣⌊((×ばつ⌊25÷⍨a←2613+(×ばつ⌊⍵÷100)-(×ばつ⌊⍵÷400))×ばつ19∣⍵)÷330}

I just copied the text, I say it was need years/generations for make something as above...Input one integer, output one data, the Easter date.

test

 E←{{(m n o)←{2≤≢⍵:⍵⋄'0',⍵} ̈⍕ ̈⍵⋄m,'-',n,'-',o}⍵,(⌊r÷31),1+31∣r←148-r+7∣(×ばつ5÷4)+a-r←29∣⌊((×ばつ⌊25÷⍨a←2613+(×ばつ⌊⍵÷100)-(×ばつ⌊⍵÷400))×ばつ19∣⍵)÷330}
 E 5701583
5701583-04-10
 E 2013
2013年03月31日
 E 1583
1583年04月10日
 E 3029
3029年03月22日
 E 1789
1789年04月12日
 E 1725
1725年04月01日

I have some duoubit for the date E 3029, here with one other program (change hacking above for use 'my' moon phase program) result

 H3 3029
3029 4 19

so a different data from above...This below is the [phase], [days to next new moon] result to me for 20 3 3029

 H 20 3 3029
5 10 
 {H ⍵ 3 3029} ̈15..30
4 15 4 14 4 13 4 12 5 11 5 10 5 9 5 8 6 7 6 6 6 5 6 4 7 3 7 2 7 1 7 0 
 15 16 17 18 19 20 | 21 21 22

so full moon has to be where there is phase 4, but it seems before 20 3 3029, and in the definition of Easter day i read "Domenica successiva alla prima luna piena di primavera". Possible H and H3 are not accurate enought can make errors of +-1.... Even if my function not agree with that too, in this link

https://moonphases.org/fullmoons/3029

result full moon for 22-03-3029 so 22-03 is not the date of Easter in 3029 because the date of Easter would be after the date [the date or the time? because change the day] of the first full moon.

answered Apr 12 at 18:12
\$\endgroup\$
0
\$\begingroup\$

Bespoke, 962 bytes

PUT XXX:I FOUR INTEIGHT
INPUT N
DO COPY
OUTPUT N
PUSH I H V
OUTPUT N
DO COPY
PUT XXX:I NUMBERZERO NUMBERZERO;STACKTOP QUOTIENTOF
DO COPY
PUT XXXX:I FOUR INTEIGHT TRI;STACKTOP PRODUCTOF
DO SWITCH
PUSH FOUR STACKTOP QUOTIENTOF
PUT XXXX:BI BI BI FIFTH;STACKTOP PRODUCTOF
STACKTOP MINUS
PUT XXXX:BI SEXTET I TRI;STACKTOP PLUS
DO COPY
PUT XX:BI FIFTH;STACKTOP QUOTIENTOF
PUT XXX:TRI I DIGITNINE;STACKTOP PRODUCTOF
PUSH TRI DO COPYN
PUT XX:I DIGITNINE;STACKTOP MODULO
PUT XXXX:TRI FIFTH I NUMBERZERO;STACKTOP PRODUCTOF
STACKTOP PLUS
PUT XXX:TRI TRI NUMBERZERO;STACKTOP QUOTIENTOF
PUT XX:BI DIGITNINE;STACKTOP MODULO
DO COPY
PUSH FOUR DO ROT
STACKTOP MINUS
DO SWITCH
PUSH FIFTH STACKTOP PRODUCTOF
PUSH FOUR STACKTOP QUOTIENTOF
STACKTOP PLUS
PUSH SEVENTH STACKTOP MODULO
STACKTOP PLUS
STACKTOP MINUS
DO COPY
PUT XX:TRI I;STACKTOP QUOTIENTOF
PUT XXX:I NUMBERZERO NUMBERZERO;STACKTOP PRODUCTOF
DO SWITCH
PUT XX:TRI I;STACKTOP MODULO
STACKTOP PLUSONE
STACKTOP PLUS
OUTPUT N

Outputs in the format YYYYMMDD. A port of the following Easter calculation function from Al Petrofsky:

function Easter20ops(YR) {
 var a = ~~(YR / 100) * 1483 - ~~(YR / 400) * 2225 + 2613;
 var b = ~~((YR % 19 * 3510 + ~~(a / 25) * 319) / 330) % 29;
 return 56 - b - (~~(YR * 5 / 4) + a - b) % 7;
 // To get Month & Day in 23 total arithmetic operations, use:
 // c = 148 - b - (~~(YR * 5 / 4) + a - b) % 7;
 // Month = ~~(c / 31);
 // Day = c % 31 + 1;
 }
answered Aug 27 at 0:46
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.