Day of week algorithm bug?

时间:2015-07-28 22:29:51

标签: java algorithm calendar

Hello I made a software that generates HTML calendar. I followed Method 1 algorithm from wiki http://www.wikihow.com/Calculate-the-Day-of-the-Week to get exact day of the week in current day for a year. But problem is that there is a bug when it goes from year 2099 to 2100 then in year 2100 it is about one day behind.

My question is... is that algorithm correct? Should it be a day back behind in year 2100? I have no time to wait 85 years to figure this out :( Also I tried Easter Sunday algorithm and it also generates Sunday on the day it should be Sunday by Day of the week algorithm so I am not sure who has the right, if me or the two correctly generating algorithms.

Here are next years what are buggy in my opinion: Testing years 0 to 2200
Incorrect day from year to year: 99/100
Incorrect day from year to year: 199/200
Incorrect day from year to year: 299/300
Incorrect day from year to year: 499/500
Incorrect day from year to year: 599/600
Incorrect day from year to year: 699/700
Incorrect day from year to year: 899/900
Incorrect day from year to year: 999/1000
Incorrect day from year to year: 1099/1100
Incorrect day from year to year: 1299/1300
Incorrect day from year to year: 1399/1400
Incorrect day from year to year: 1499/1500
Incorrect day from year to year: 1699/1700
Incorrect day from year to year: 1799/1800
Incorrect day from year to year: 1899/1900
Incorrect day from year to year: 2099/2100

*EDIT
Here is algorithm to get Easter Sunday:

int c = year/100;
int n = year - 19*(int)(year/19);
int k = (c - 17)/25;
int i = c - (int)(c/4) - (int)((c - k)/3) + 19*n + 15;
i -= 30*(int)(i/30);
i -= (int)(i/28)*(1 - (int)(i/28)*(int)(29/(i + 1))*(int)((21 - n)/11));
int j = year + (int)(year/4) + i + 2 - c + (int)(c/4);
j -= 7*(int)(j/7);
int l = i - j;
int m = 3 + (int)((l + 40)/44); //Your month when is Easter Sunday
int d = l + 28 - 31*(int)(m/4); //Your day when is Easter Sunday

Here is algorithm to get day of the week in a Year Month Day

int [] CENTURY_TABLE = {0, 5, 3, 1};
int [] MONTH_TABLE = {0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5};
boolean leap = false;
int t1 = (day + MONTH_TABLE[month - 1]) % 7;
int m1 = year % 100;
int t2 = (m1 % 7) + (m1/4) + CENTURY_TABLE[((int)(year/100)) % CENTURY_TABLE.length] - (leap  &&  (month == 1  || month == 2) ? 1 : 0);
if(t2 == -1){
    t2 = 6;
}
int d = (t1 + t2) % 7;  //0 - Saturday, 1 - Sunday, 2 - Monday... 6 - Friday

*FIX
Change "leap" summary in Day of Week algorithm to

leap = year % 4 == 0  &&  (year % 100 == 0 ? year % 400 == 0 : true) //This fixed my problem <3

1 个答案:

答案 0 :(得分:1)

I think your program is affected by leap years: https://en.wikipedia.org/wiki/Leap_year

You have a problem on all years dividable through 100 but not 400.

Edit after select as solution:

The code works without problems. I slightly changed for a test and got no error:

@Test
public void dayTest()
{
    for (int y = 2099; y <=2100; y++)
    {
        int day = easterSundayDay(y);
        int month = easterSundayMonth(y);

        assertTrue("Wrong year: " + day + "."+ month + "."+ y + " is day: " + dayOfWeek(day, month, y), 1 ==dayOfWeek(day, month, y));
    }
}

public int easterSundayDay(int year)
{
    int c = year/100;
    int n = year - 19*(int)(year/19);
    int k = (c - 17)/25;
    int i = c - (int)(c/4) - (int)((c - k)/3) + 19*n + 15;
    i -= 30*(int)(i/30);
    i -= (int)(i/28)*(1 - (int)(i/28)*(int)(29/(i + 1))*(int)((21 - n)/11));
    int j = year + (int)(year/4) + i + 2 - c + (int)(c/4);
    j -= 7*(int)(j/7);
    int l = i - j;
    int m = 3 + (int)((l + 40)/44); //Your month when is Easter Sunday
    int d = l + 28 - 31*(int)(m/4);

    return d;
}

public int easterSundayMonth(int year)
{
    int c = year/100;
    int n = year - 19*(int)(year/19);
    int k = (c - 17)/25;
    int i = c - (int)(c/4) - (int)((c - k)/3) + 19*n + 15;
    i -= 30*(int)(i/30);
    i -= (int)(i/28)*(1 - (int)(i/28)*(int)(29/(i + 1))*(int)((21 - n)/11));
    int j = year + (int)(year/4) + i + 2 - c + (int)(c/4);
    j -= 7*(int)(j/7);
    int l = i - j;
    int m = 3 + (int)((l + 40)/44); //Your month when is Easter Sunday
    int d = l + 28 - 31*(int)(m/4);

    return m;
}
public int dayOfWeek(int day, int month, int year)
{
    int [] CENTURY_TABLE = {0, 5, 3, 1};
    int [] MONTH_TABLE = {0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5};
    boolean leap = false;
    int t1 = (day + MONTH_TABLE[month - 1]) % 7;
    int m1 = year % 100;
    int t2 = (m1 % 7) + (m1/4) + CENTURY_TABLE[((int)(year/100)) % CENTURY_TABLE.length] - (leap  &&  (month == 1  || month == 2) ? 1 : 0);
    if(t2 == -1){
        t2 = 6;
    }
    int d = (t1 + t2) % 7;

    return d;
}