views:

626

answers:

8

Does anyone have a good algorithm to calculate what date Good Friday falls on given the year as an input? Preferably in C#.

+1  A: 

There's an online calculator here:

http://mb-soft.com/believe/txx/easter01.htm

It's written in pure javascript, and the script source is right there in the .html file. I'd mine it for algorithms and translate as appropriate.

Randolpho
+9  A: 

Here's a great article that should help you build your algorithm

http://www.codeproject.com/KB/datetime/christianholidays.aspx

Based on this example, you should be able to write:

DateTime goodFriday = EasterSunday(DateTime.Now.Year).AddDays(-2);

Full Example:

public static DateTime EasterSunday(int year)
{
    int day = 0;
    int month = 0;

    int g = year % 19;
    int c = year / 100;
    int h = (c - (int)(c / 4) - (int)((8 * c + 13) / 25) + 19 * g + 15) % 30;
    int i = h - (int)(h / 28) * (1 - (int)(h / 28) * (int)(29 / (h + 1)) * (int)((21 - g) / 11));

    day   = i - ((year + (int)(year / 4) + i + 2 - c + (int)(c / 4)) % 7) + 28;
    month = 3;

    if (day > 31)
    {
        month++;
        day -= 31;
    }

    return new DateTime(month, day, year);
}
hunter
+1 I like that one.
Randolpho
int h = h = ( ??? Is one of those assignment operators a typo?
Eric Lippert
I don't know what you're referring to... j/k, I fixed it
hunter
I can't believe how complex that is for something so seemingly simple... I wonder if I can refactor that... (wonders)
hunter
You could refactor it to have meaningful variable names...
Sarah Vessels
@Sarah And what would you suggest for year mod 19? int yearMod19?
hunter
@Sarah If you clicked the link in my post you'll see I used the example from that link
hunter
@Hunter: `yearMod19` is more informative than `g`!
Sarah Vessels
@Sarah I guess the point is that it is really meaningless anyway. I think with algorithms meaningful names can be ignored when there's no meaningful name to give. for(int incrementingInteger = 0; incrementingInteger < blah.Count(); incrementingInteger++) <= If I see you write that I will be very sad
hunter
@Hunter: for a loop like that, the `int` could easily be an index into something, so `gooseIndex` would be more appropriate. Not that I do this, I usually do `i` or `j` or whatever, but I had a prof that insisted on no meaningless variable names, even in loops...
Sarah Vessels
+2  A: 

Wikipedia knows: http://en.wikipedia.org/wiki/Good_Friday#Calculating_the_date

Good Friday is the Friday before Easter, which is calculated differently in Eastern Christianity and Western Christianity (see Computus for details). Easter falls on the first Sunday following the Paschal Full Moon, the full moon on or after 21 March, taken to be the date of the vernal equinox. The Western calculation uses the Gregorian calendar, while the Eastern calculation uses the Julian calendar, whose 21 March now corresponds to the Gregorian calendar's 3 April. The calculations for identifying the date of the full moon also differ. See Easter Dating Method (Astronomical Society of South Australia).

In Eastern Christianity, Easter can fall between March 22 and April 25 on Julian Calendar (thus between April 4 and May 8 in terms of the Gregorian calendar, during the period 1900 and 2099), so Good Friday can fall between March 20 and April 23, inclusive (or between April 2 and May 6 in terms of the Gregorian calendar). (See Easter.)

Matt Ball
also see http://en.wikipedia.org/wiki/Computus (which may or may not be linked from that wikipedia entry). One method that has been used historically is table lookup -- don't discount this method (unless of course your question is for homework :-)
Gordon Broom
Computus link is in there.
Matt Ball
+5  A: 

Don't Repeat Yourself

Think

Realize that calculating Easter is what you are really dependent upon.

Research

Here is the offical Naval Observatory page for calculating Easter.

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

Execute

Use the formula for calculating Easter then shift to the previous Friday (or subtract 2 days, details up to you).

Kelly French
A: 

It's not C# but you might want to have a look here.

TLiebe
+1  A: 

Try this:

// test code:
Console.WriteLine(CalcGoodFri(2008));
Console.WriteLine(CalcGoodFri(2009));
Console.WriteLine(CalcGoodFri(2010));

private static DateTime CalcGoodFri(int yr)
{
 //int yr = 2010;  // The year for which to determine the date of Good Friday.
 int a = yr % 19;      
 int b = yr / 100;     
 int c = yr % 100;   
 int d = b / 4;
 int e = b % 4;      
 int i = c / 4;
 int k = c % 4;
 int g = (8 * b + 13) / 25;
 int h = ((19 * a) + b - d - g + 15) % 30;
 int l = ((2 * e) + (2 * i) - k + 32 - h) % 7;
 int m = (a + (11*h) + (19*l)) / 433;
 int days_to_good_friday = h + l - (7*m) - 2;  
 int mo = (days_to_good_friday + 90) / 25;
 int da = (days_to_good_friday + (33 * mo) + 19) % 32;
 return new DateTime ( yr, mo, da) ;    // Returns the date of Good Friday
}

Logic ported from here: http://www.kenhamady.com/form25.shtml

Paul Sasik
A: 

A quick note to non-US coders trying out Hunter's code: for the last line you should use ISO constructor new DateTime(year, month, day); :)

kaarel