Code Golf: Calculate Orthodox Easter date
Asked Answered
G

14

25

The Challenge

Calculate the Date of the Greek Orthodox Easter (http://www.timeanddate.com/holidays/us/orthodox-easter-day) Sunday in a given Year (1900-2100) using the least amount of characters.

Input is just a year in the form '2010'. It's not relevant where you get it (Input, CommandLineArgs etc.) but it must be dynamic!

Output should be in the form day-month-year (say dd/mm/yyyy or d/m/yyyy)

Restrictions No standard functions, such as Mathematica's EasterSundayGreekOrthodox or PHP's easter_date(), which return the (not applicable gregorian) date automatic must be used!

Examples

2005 returns 1/5/2005
2006 returns 23/4/2006
2007 returns 8/4/2007
2008 returns 27/4/2008
2009 returns 19/4/2009
2010 returns 4/4/2010
2011 returns 24/4/2011
2012 returns 15/4/2012
2013 returns 5/5/2013
2014 returns 20/4/2014
2015 returns 12/4/2015

Code count includes input/output (i.e full program).

Edit: I mean the Eastern Easter Date.

Reference: http://en.wikipedia.org/wiki/Computus

Greenfield answered 27/8, 2010 at 12:54 Comment(18)
Yup wiki or its just a rep grab....Creon
no standard functions? Isn't that reinventing the wheel then? Also Easter Sunday was April, 4thSimplism
Why is this 'not a real question'?Lure
@Bolt: because it was not a CW in first instance. Now it is, close voters will stop and the current votes will disappear after a while.Enfleurage
In haskell it would be easy.. But the amount of characters used for defining all the functions are a lot.. At least you need to define the "+" function, the "mod" function and the "*" function. Maybe >, =, and <. Well.. you should define the "natural" data type, or the "date" data type..Khalkha
@BalusC: I still vote to close every Code Golf question I see, even if it is community wiki. I think they are annoying and pure noise - they add nothing of value to the community, IMO.Combo
@Enfleurage I stand by my closevote too unless the OP removes the restriction. Code Golf is to show-off in the least possible keystrokes. If my pet-language has a built-in function for calculating easter sunday, then I insist on using it.Simplism
@Thomas Owens. I find them very useful for comparing languages. Small problems with solutions in a number of languages. Granted that many solutions are obfuscated in an attempt to reduce character count. Sometimes I even learn a new language construct or algorithm. But do they fit the stated MO of SO? Probably not.Strife
@Strife Don't get me wrong, I like Code Golf. Just not here on Stack Overflow. Perhaps there should be a Code Golf Stack Exchange?Combo
There is a minimum standard for code-golf questions on SO meta.stackexchange.com/questions/24242Soloman
@Thomas: Last time I looked the pro-code-golf side has a solid consensus. You'll note that my answer is agin, but at nearly five-to-one you won't win that argument. Instead, I lean heavily on maintaining [the standards from gnibbler's link(meta.stackexchange.com/questions/24242).Mastat
@Gordon: Concerning built-in's: you don't prove anything about your own guile and skeakiness (aside from the "funny once" built-to-purpose-language answer) that way.Mastat
Besides, there is no standard library function for the Eastern Orthodox Easter: easter_date() computes the Western Easter, and it doesn't even put it in the requested format.Dorella
@Thomas There is, and it's barely moved. I'm considering posting every new code golf question I see as an example on-topic question there; I could even script itKeli
I'm curious to see how many of these handle Year 0 which does not actually exist.Decolorize
@theycallmemorty: A lot of these algorithms have domains that are considerably smaller than the theoretical range of the Gregorian or Julian calendar. The issue is that the date of Easter depends on the ecclesiastical moon. The real moon's motion doesn't really fit as neatly as the algorithms assume, and the ecclesiastical rules are even more obscure (and have been Just Plain Wrong for substantial periods in the past too). en.wikipedia.org/wiki/Computus gives far more info than you ever really wanted on the topic…Critique
Do the programs need to include the year 2100? many do not.Neap
David, according to the leap shifting of the Gregorian calendar, I would assume the 1900-2100 range is half-open ([1900, 2100)), unless Mr. Banov specifies otherwise.Underdone
E
9

Python (101 140 132 115 chars)

y=input()
d=(y%19*19+15)%30
e=(y%4*2+y%7*4-d+34)%7+d+127
m=e/31
a=e%31+1+(m>4)
if a>30:a,m=1,5
print a,'/',m,'/',y

This one uses the Meeus Julian algorithm but since this one only works between 1900 and 2099, an implementation using Anonymous Gregorian algorithm is coming right up.

Edit: Now 2005 is properly handled. Thanks to Mark for pointing it out.

Edit 2: Better handling of some years, thanks for all the input!

Edit 3: Should work for all years in range. (Sorry for hijacking it Juan.)

Estrin answered 27/8, 2010 at 12:54 Comment(9)
You can shorten that by using operator precedence cleverly.Critique
@Donal: I actually tried playing around with precedence, but I couldnt find anything to shorten.Timoshenko
Fails for 1907: should be 05/05/1907, output is 04/05/1907. Looks like it's because the check you added for May assumes the latest Easter can be is May 1st.Dorella
Also, the Anonymous Gregorian algorithm won't calculate the Eastern Orthodox (Julian) Easter. If you wanted to take into account dates outside the 1900-2100 range, you'd need to check the year and add the appropriate number of days.Dorella
Fails for 2013: gives May 4th, should be May 5th: timeanddate.com/holidays/us/orthodox-easter-dayGreenfield
And I just messed things up even further. Cleary I dont remember what I learned in algebra..Timoshenko
@Nas Banov: I think I fixed it for that year.Snappish
@Juan: You got the thing I spotted: a*(b%c) can go to b%c*a (provided there's no side effects in the way) for a saving of 2 chars.Critique
The result for 2100 should be 2 / 5/ 2100, not 1 / 5/ 2100Neap
D
4

C#, 155 157 182 209 212 characters

class P{static void Main(string[]i){int y=int.Parse(i[0]),c=(y%19*19+15)%30,d=c+(y%4*2+y%7*4-c+34)%7+128;System.Console.Write(d%31+d/155+"/"+d/31+"/"+y);}}

Python 2.3, 97 characters

y=int(input())
c=(y%19*19+15)%30
d=c+(y%4*2+y%7*4-c+34)%7+128
print"%d/%d/%d"%(d%31+d/155,d/31,y)

This also uses the Meeus Julian algorithm (and should work for dates in May).

  • removed no longer necessary check for modern years and zero-padding in output
  • don't expect Easters in March anymore because there are none between 1800-2100
  • included Python 2.3 version (shortest so far)
Darwinism answered 27/8, 2010 at 12:54 Comment(5)
what does this print for 2100?Neap
The result for 2100 should be 2 / 5 / 2100. Not 1 / 5 / 2100Neap
The actual range of the algorithm is between 1900 and 2099 inclusive, which presumably is what the rule means when it says "(1900-2100)".Darwinism
Oh, I read 1900-2100 as 1900 THROUGH 2100...which would include the year 2100. Even if you read it as 1900 TO 2100 you should still count 2100, right? I someone told you to count from 1 TO 10 would you stop at 9?Neap
David: I just meant that it was a bug in the spec. The algorithm works for dates from 13 March 1900 to 13 March 2100. It just turns out that Easter for 2100 is after that last date.Darwinism
L
4

PHP CLI, no easter_date(), 125 characters

Valid for dates from 13 March 1900 to 13 March 2100, now works for Easters that fall in May

Code:

<?=date("d/m/Y",mktime(0,0,0,floor(($b=($a=(19*(($y=$argv[1])%19)+15)%30)+(2*($y%4)+4*$y%7-$a+34)%7+114)/31),($b%31)+14,$y));

Invocation:

$ php codegolf.php 2010
$ php codegolf.php 2005

Output:

04/04/2010
01/05/2005

With whitespace:

<?=date("d/m/Y", mktime(0, 0, 0, floor(($b = ($a = (19 * (($y = $argv[1]) % 19) + 15) % 30) + (2 * ($y % 4) + 4 * $y % 7 - $a + 34) % 7 + 114) / 31), ($b % 31) + 14, $y));

This iteration is no longer readable thanks to PHP's handling of assignments. It's almost a functional language!


For completeness, here's the previous, 127 character solution that does not rely on short tags:

Code:

echo date("d/m/Y",mktime(0,0,0,floor(($b=($a=(19*(($y=$argv[1])%19)+15)%30)+(2*($y%4)+4*$y%7-$a+34)%7+114)/31),($b%31)+14,$y));

Invocation:

$ php -r 'echo date("d/m/Y",mktime(0,0,0,floor(($b=($a=(19*(($y=$argv[1])%19)+15)%30)+(2*($y%4)+4*$y%7-$a+34)%7+114)/31),($b%31)+14,$y));' 2010
$ php -r 'echo date("d/m/Y",mktime(0,0,0,floor(($b=($a=(19*(($y=$argv[1])%19)+15)%30)+(2*($y%4)+4*$y%7-$a+34)%7+114)/31),($b%31)+14,$y));' 2005
Litigation answered 27/8, 2010 at 12:54 Comment(8)
The question is for the Eastern (Julian) date, so we're not interested in the Gregorian date. As you mention the calendars are different so you have to adjust the dates for certain years. Your Julian output does not satisfy the required output in the question. See my JS solution, which accounts for the date difference.Hersh
What does your program print for 2005?Darwinism
@Gabe, previously the awesome day of April 31st. I've fixed this at the expense of more characters, so now it's May 1st.Dorella
I don't mean to be annoying, but how can this be considered a solution when it only works for a range of 200 years?Hersh
@Josh Leitzel, all of the Meeus algorithm answers, including your own, fail when the year is outside the bounds of 1900 and 2100. You even put a check in yours for this condition.Dorella
Just as a clarification, this is because of the Julian to Gregorian calendar conversion. Adding 13 days only works for dates between 1900 and 2100: see Wikipedia for the table.Dorella
what does this print for 2100?Neap
@David Murdoch: nothing correct, as the Julian conversion fails for dates after the stated March 13, 2100 (which the Eastern Easter certainly is after).Dorella
E
4

Mathematica

<<Calendar`;a=Print[#3,"/",#2,"/",#]&@@EasterSundayGreekOrthodox@#&

Invoke with

a[2010]

Output

4/4/2010

Me too: I don't see the point in not using built-in functions.

Eliza answered 27/8, 2010 at 12:54 Comment(7)
Because the point is to show how you can do it in as few keystrokes as possible not to show that your languages library has every imaginable function.Chimaera
If your language's library has every imaginable function, then you can do it in very few keystrokes.Pennate
So, lets print without "Print", add without "+" and program without variables, just to pose other artificial restrictions that affect languages unevenly. The only way to restrict language features fairly is to propose a code-golf in only one language.Tandem
BTW, forbid using a stack in obviously recursive problems seems to be very creative too!Tandem
@Darwinism a[2005] printed 27/3/2005 ... now fixed .. prints 1/5/2005Tandem
how could you complain about imposing artificial restrictions on a code golf?? it's for fun; if you're not having fun, go elsewhere.Culbreth
Perhaps this function should be added to the GolfScript standard library, since it's getting so much demand?Tolley
E
3

Java - 252 196 190 chars


  • Update 1: The first algo was for Western Gregorian Easter. Fixed to Eastern Julian Easter now. Saved 56 chars :)

  • Update 2: Zero padding seem to not be required. Saved 4 chars.


class E{public static void main(String[]a){long y=new Long(a[0]),b=(y%19*19+15)%30,c=b+(y%4*2+y%7*4-b+34)%7+(y>1899&y<2100?128:115),m=c/31;System.out.printf("%d/%d/%d",c%31+(m<5?0:1),m,y);}}

With newlines

class E{
 public static void main(String[]a){
  long y=new Long(a[0]),
  b=(y%19*19+15)%30,
  c=b+(y%4*2+y%7*4-b+34)%7+(y>1899&y<2100?128:115),
  m=c/31;
  System.out.printf("%d/%d/%d",c%31+(m<5?0:1),m,y);
 }
}
Enfleurage answered 27/8, 2010 at 12:54 Comment(2)
Please tell me you didn't include the spaces in y = new in your golf stroke count!Darwinism
@Gabe: that was an oversight :)Enfleurage
C
2

Tcl

Eastern Easter

(116 chars)

puts [expr 1+[incr d [expr ([set y $argv]%4*2+$y%7*4-[
set d [expr ($y%19*19+15)%30]]+34)%7+123]]%30]/[expr $d/30]/$y

Uses the Meeus algorithm. Takes the year as a command line argument, produces Eastern easter. Could be a one-liner, but it's slightly more readable when split...

Western Easter

(220 chars before splitting over lines)

interp alias {} tcl::mathfunc::s {} set;puts [expr [incr 3 [expr {
s(2,(s(4,$argv)%100/4*2-s(3,(19*s(0,$4%19)+s(1,$4/100)-$1/4-($1-($1+8)/25+46)
/3)%30)+$1%4*2-$4%4+4)%7)-($0+11*$3+22*$2)/451*7+114}]]%31+1]/[expr $3/31]/$4

Uses the Anonymous algorithm.

Critique answered 27/8, 2010 at 12:54 Comment(3)
It's also a shameless ripoff of this other answer: https://mcmap.net/q/531422/-code-golf-calculate-orthodox-easter-date/…Critique
what does this output for year 2100?Neap
@David: First snippet, 1/5/2100, second snippet, 28/3/2100. Don't know if they're correct; the algorithms are known to have limited domains.Critique
H
2

JavaScript (196 characters)

Using the Meeus Julian algorithm. This implementation assumes that a valid four-digit year was given.

y=~~prompt();d=(19*(y%19)+15)%30;x=d+(2*(y%4)+4*(y%7)-d+34)%7+114;m=~~(x/31);d=x%31+1;if(y>1899&&y<2100){d+=13;if(m==3&&d>31){d-=31;m++}if(m==4&&d>30){d-=30;m++}}alert((d<10?"0"+d:d)+"/0"+m+"/"+y)
Hersh answered 27/8, 2010 at 12:54 Comment(7)
What does your program print for 2005?Darwinism
You don't need the window.onload bit.Antepenult
@Darwinism Fixed. (Nonexistent date of 31/04/2005 was output before.)Hersh
@Casey I kept it because OP asked for a 'full program,' not a function.Hersh
Fails for years outside 1900 and 2100: 1875 should be 25/04/1875, program outputs 13/04/1875; 2200 should be 18/04/2123, program outputs 04/04/2123. This is because Julian conversion to Gregorian uses an algorithm to determine how many days to add. Your program adds the correct amount for 1900-2100, but adds nothing for other dates. I don't think it's a requirement that it should work for dates outside 1900-2100, but you mentioned it as a possible requirement.Dorella
You can still have a full program by omitting window.onload=function(){ -- execution will simply start immediately instead of on load.Antepenult
Improved the script using ~~ and removing it from the window.onloadToler
A
2

Delphi 377 335 317 characters

Single line:

var y,c,n,i,j,m:integer;begin Val(ParamStr(1),y,n);c:=y div 100;n:=y-19*(y div 19);i:=c-c div 4-(c-((c-17)div 25))div 3+19*n+15;i:=i-30*(i div 30);i:=i-(i div 28 )*(1-(i div 28)*(29 div(i+1))*((21 -n)div 11));j:=y+y div 4 +i+2-c+c div 4;j:=j-7*(j div 7);m:=3+(i-j+40 )div 44;Write(i-j+28-31*(m div 4),'/',m,'/',y)end.

Formatted:

var
  y,c,n,i,j,m:integer;
begin
  Val(ParamStr(1),y,n);
  c:=y div 100;
  n:=y-19*(y div 19);
  i:=c-c div 4-(c-((c-17)div 25))div 3+19*n+15;
  i:=i-30*(i div 30);
  i:=i-(i div 28 )*(1-(i div 28)*(29 div(i+1))*((21 -n)div 11));
  j:=y+y div 4 +i+2-c+c div 4;j:=j-7*(j div 7);
  m:=3+(i-j+40 )div 44; 
  Write(i-j+28-31*(m div 4),'/',m,'/',y)
end.
Al answered 27/8, 2010 at 12:54 Comment(0)
P
1

C, 128 121 98 characters

Back to Meeus' algorithm. Computing the day in Julian, but adjusting for Gregorian (this still seems naive to me, but I cannot find a shorter alternative).

main(y,v){int d=(y%19*19+15)%30;d+=(y%4*2+y%7*4-d+34)%7+128;printf("%d/%d/%d",d%31+d/155,d/31,y);}

I have not found a case where floor(d/31) would actually be needed. Also, to account for dates in May, the m in Meeus' algorithm must be at least 5, therefore the DoM is greater than 154, hence the division.

The year is supplied as the number of program invocation arguments plus one, ie. for 1996 you must provide 1995 arguments. The range of ARG_MAX on modern systems is more than enough for this.

PS. I see Gabe has come to the same implementation in Python 2.3, surpassing me by one character. Aw. :( PPS. Anybody looking at a tabular method for 1800-2099?

Edit - Shortened Gabe's answer to 88 characters:

y=input()
d=(y%19*19+15)%30
d+=(y%4*2+y%7*4-d+34)%7+128
print"%d/%d/%d"%(d%31+d/155,d/31,y)
Peba answered 27/8, 2010 at 12:54 Comment(2)
what does this output for year 2100?Neap
For 2100, the year when the Julian-Gregorian calendars' difference increases by 1 day, it outputs 1/5/2100.Underdone
M
1

COBOL, 1262 chars

WORKING-STORAGE SECTION.

01 V-YEAR       PIC S9(04) VALUE 2010.
01 V-DAY        PIC S9(02) VALUE ZERO.
01 V-EASTERDAY  PIC S9(04) VALUE ZERO.
01 V-CENTURY    PIC S9(02) VALUE ZERO.
01 V-GOLDEN     PIC S9(04) VALUE ZERO.
01 V-GREGORIAN  PIC S9(04) VALUE ZERO.
01 V-CLAVIAN    PIC S9(04) VALUE ZERO.
01 V-FACTOR     PIC S9(06) VALUE ZERO.
01 V-EPACT      PIC S9(06) VALUE ZERO.

PROCEDURE DIVISION

XX-CALCULATE EASTERDAY.

   COMPUTE V-CENTURY = (V-YEAR / 100) + 1
   COMPUTE V-GOLDEN= FUNCTION MOD(V-YEAR, 19) + 1
   COMPUTE V-GREGORIAN = (V-CENTURY * 3) / 4 - 12
   COMPUTE V-CLAVIAN
        = (V-CENTURY * 8 + 5) / 25 - 5 - V-GREGORIAN
   COMPUTE V-FACTOR
        = (V-YEAR * 5) / 4 - V-GREGORIAN - 10
   COMPUTE V-EPACT
   = FUNCTION MOD((V-GOLDEN * 11 + 20 + V-CLAVIAN), 30)

   IF V-EPACT = 24
      ADD 1 TO V-EPACT
   ELSE
      IF V-EPACT = 25
         IF V-GOLDEN > 11
            ADD 1 TO V-EPACT
         END-IF
      END-IF
   END-IF

  COMPUTE V-DAY = 44 - V-EPACT

  IF V-DAY < 21
     ADD 30 TO V-DAY
  END-IF

  COMPUTE V-DAY
  = V-DAY + 7 - (FUNCTION MOD((V-DAY + V-FACTOR), 7))

  IF V-DAY <= 31
     ADD 300 TO V-DAY GIVING V-EASTERDAY
  ELSE
     SUBTRACT 31 FROM V-DAY
     ADD 400 TO V-DAY GIVING V-EASTERDAY
  END-IF
  .
XX-EXIT.
   EXIT.

Note: Not mine, but I like it

EDIT: I added a char count with spaces but I don't know how spacing works in COBOL so I didn't change anything from original. ~vlad003

UPDATE: I've found where the OP got this code: http://www.tek-tips.com/viewthread.cfm?qid=31746&page=112. I'm just putting this here because the author deserves it. ~vlad003

Mould answered 27/8, 2010 at 12:54 Comment(4)
You should note what language/platform this is.Buffoon
I don't think it will compile without headers. What compiler are you using?Tandem
If it is not yours, you should tell whose it is. It might even be a copyright violation.Merill
Please cite your source. (+1 @Andreas Rejbrand)Driblet
N
0

Javascript 125 characters

This will handle years 1900 - 2199. Some of the other implementations cannot handle the year 2100 correctly.

y=prompt();k=(y%19*19+15)%30;e=(y%4*2+y%7*4-k+34)%7+k+127;m=~~(e/31);d=e%31+m-4+(y>2099);alert((d+=d<30||++m-34)+"/"+m+"/"+y)

Ungolfed..ish

// get the year to check.
y=prompt();

// do something crazy.
k=(y%19*19+15)%30;

// do some more crazy...
e=(y%4*2+y%7*4-k+34)%7+k+127;

// estimate the month. p.s. The "~~" is like Math.floor
m=~~(e/31);

// e % 31 => get the day
d=e%31;
if(m>4){
    d += 1;
}
if(y > 2099){
   d += 1;
}

// if d is less than 30 days add 1
if(d<30){
   d += 1;
}
// otherwise, change month to May
// and adjusts the days to match up with May.
// e.g., 32nd of April is 2nd of May
else{
    m += 1;
    d = m - 34 + d;
}

// alert the result!
alert(d + "/" + m + "/" + y);

A fix for dates up to 2399.
I'm sure there is a way to algorithmically calculate dates beyond this but I don't want to figure it out.

y=prompt();k=(y%19*19+15)%30;e=(y%4*2+y%7*4-k+34)%7+k+127;m=~~(e/31);d=e%31+m-4+(y<2200?0:~~((y-2000)/100));alert((d+=d<30||++m-34)+"/"+m+"/"+y)
Neap answered 27/8, 2010 at 12:54 Comment(0)
T
0

I'm not going to implement it, but I'd like to see one where the code e-mails the Pope, scans any answer that comes back for a date, and returns that.

Admittedly, the calling process may be blocked for a while.

Thumbscrew answered 27/8, 2010 at 12:54 Comment(1)
So far it's been blocked since the 5th century. It asks for the orthodox easter date - the guy with the big hat in Rome works for the other lotKalindi
S
0
'VB .Net implementation of:
'http://aa.usno.navy.mil/faq/docs/easter.php
Dim y As Integer = 2010
Dim c, d, i, j, k, l, m, n As Integer
c = y \ 100
n = y - 19 * (y \ 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 - (i \ 28) * (29 \ (i + 1)) * ((21 - n) \ 11))
j = y + y \ 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)
Easter = DateSerial(y, m, d)
Schoolman answered 27/8, 2010 at 12:54 Comment(0)
M
0

BASIC, 973 chars

Sub EasterDate (d, m, y)

   Dim FirstDig, Remain19, temp    'intermediate results
   Dim tA, tB, tC, tD, tE          'table A to E results

   FirstDig = y \ 100              'first 2 digits of year
   Remain19 = y Mod 19             'remainder of year / 19

' calculate PFM date
   temp = (FirstDig - 15) \ 2 + 202 - 11 * Remain19

   Select Case FirstDig
      Case 21, 24, 25, 27 To 32, 34, 35, 38
         temp = temp - 1
      Case 33, 36, 37, 39, 40
         temp = temp - 2
   End Select
   temp = temp Mod 30

   tA = temp + 21
   If temp = 29 Then tA = tA - 1
   If (temp = 28 And Remain19 > 10) Then tA = tA - 1

'find the next Sunday
   tB = (tA - 19) Mod 7

   tC = (40 - FirstDig) Mod 4
   If tC = 3 Then tC = tC + 1
   If tC > 1 Then tC = tC + 1

   temp = y Mod 100
   tD = (temp + temp \ 4) Mod 7

   tE = ((20 - tB - tC - tD) Mod 7) + 1
   d = tA + tE

'return the date
   If d > 31 Then
      d = d - 31
      m = 4
   Else
      m = 3
   End If

End Sub

Credit: Astronomical Society of South Australia

EDIT: I added a char count but I think many spaces could be removed; I don't know BASIC so I didn't make any changes to the code. ~vlad003

Mould answered 27/8, 2010 at 12:54 Comment(3)
I added it myself, but you may want to remove spaces to lower the count.Chimaera
BASIC is a hilarious programming language I have to say. What does (temp + temp \ 4) do? What is the \ operator?Culbreth
@tenfour: According to Wikipedia: "In some dialects of the BASIC programming language, the backslash is used as an operator symbol to indicate integer division."Chimaera

© 2022 - 2024 — McMap. All rights reserved.