复活节日期的计算
package cn.ancony.chinese_calendar;
/**
* 计算指定年基督教复活节星期日(Easter Sunday)日期的方法
*/
public class EasterSunday {
/**
* 复活节星期日的推算规则:春分后(含春分)的第一次满月后的第一个星期日。
* <p>
* 在 1900 至 2100 年间,使用纯粹天文规则推算出了一些不同于教会规则的复活节星期日,这些年份是:
* <p>
* 1900,1903,1923,1924,1927,1943,1954,1962,1967,
* 1974,1981,2038,2049,2069,2076,2089,2095,2096.
*
* @param year 年份,1582年(不含)后使用格里高利历,之前使用儒略历
* @return 复活节日期
*/
public static YearMonthDay easterSunday(int year) {
return year > 1582 ? gregorian(year) : julian(year);
}
/**
* 格里高利复活节
* 适用于格里高利历中始自 1583 年的所有年份.
* 格里高利历的复活节日期要 5700000 年才循环一次。有人发现格复活节最常见的日期是 4 月 19 日
*
* @param year 格里高利历年份
* @return 日期
*/
private static YearMonthDay gregorian(int year) {
int
a = year % 19, b = year / 100, c = year % 100, d = b / 4,
e = b % 4, f = (b + 8) / 25, g = (b - f + 1) / 3,
h = (19 * a + b - d - g + 15) % 30, i = c / 4, k = c % 4,
l = (32 + 2 * e + 2 * i - h - k) % 7, m = (a + 11 * h + 22 * l) / 451,
tmp = (h + l - 7 * m + 114), n = tmp / 31, p = tmp % 31;
return YearMonthDay.of(year, n, p + 1);
}
/**
* 儒略历复活节
* 儒略历的复活节日期有为期 532 年的循环。比如,179 年,711 年和 1243 年的复活节都在 4 月 12 日
*
* @param year 儒略历年份
* @return 日期
*/
private static YearMonthDay julian(int year) {
int a = year % 4, b = year % 7, c = year % 19, d = (19 * c + 15) % 30,
e = (2 * a + 4 * b - d + 34) % 7,
temp = d + e + 114, f = temp / 31, g = temp % 31;
return YearMonthDay.of(year, f, g + 1);
}
}
以下是测试类:
package cn.ancony.javafx.chinese_calendar;
import cn.ancony.chinese_calendar.EasterSunday;
import cn.ancony.chinese_calendar.YearMonthDay;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class TestEasterSunday {
@ParameterizedTest
@CsvSource({
"3, 31, 1991",
"4, 19, 1992",
"4, 11, 1993",
"4, 18, 1954",
"4, 23, 2000",
"3, 22, 1818",
"3, 22, 2285",
"4, 25, 1886",
"4, 25, 1943",
"4, 25, 2038",
"4, 12, 179",
"4, 12, 711",
"4, 12, 1243"})
public void test1(int month, int day, int year) {
assertEquals(YearMonthDay.of(year, month, day), EasterSunday.easterSunday(year));
}
}