概述

毕设要做万年历,但是对阴阳历了解不多,在此总结。

阳历

阳历,就是“太阳历”,是依据太阳的变化(严格来说,应该是地球围绕太阳运动时,人在地球上所观测到的太阳的变化)来修订的历法,以地球绕太阳一圈的时间为一年。

小时候老师教过:“一三五七八十腊,三十一天永不差”。

阳历有很强的规律性,每年12个月,1、3、5、7、8、10、12月都为31天,2月份平年28天,闰年29天,其余月份为30天。是否闰年也好算,能被100整除的年份中能被400整除的是闰年,不能被100整除的年份中能被4整除的是闰年。

阴历

简介

阴历,也就是“月亮历”,是依据月亮的变化来修订的历法。月亮每经历一次从圆到缺的循环,就是一个月。我国古人常把月亮叫做“太阴”,所以也叫“阴历”。

阴历全年12个月的总天数是354.3672天,它同季节变化的周期——阳历1年365.2422天)相差约11天。阴历分大小月:大月30天、小月29天。由于这样算与阳历有差别,会不能正确反映季节,我国就创造了一种带有一定阳历成分的阴历———“阴阳合历”,也就是农历,又叫夏历(夏朝开始的)。

阴历同阳历一年相差11天。因此,农历每3年需要闰(增加)1个月,5年闰2个月,7年闰3个月,19年闰7个月,周而复始,有闰月的那一年就被称为闰年。这种设置闰月的方法叫“19年7闰法”。

因此,阴历平年12个月,闰年13个月。

算法

这根本就没规律嘛!!

所以我们要从观测阴历的天文台处得到阴历数据,网上大多是1900年到2100年的数据(根本不是万年历啊摔(/゚Д゚)/)。那么我们先从数据入手。

数据

网上搜集:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
0x04bd8,0x04ae0,0x0a570,0x054d5,0x0d260,0x0d950,0x16554,0x056a0,0x09ad0,0x055d2,//1900-1909
0x04ae0,0x0a5b6,0x0a4d0,0x0d250,0x1d255,0x0b540,0x0d6a0,0x0ada2,0x095b0,0x14977,//1910-1919
0x04970,0x0a4b0,0x0b4b5,0x06a50,0x06d40,0x1ab54,0x02b60,0x09570,0x052f2,0x04970,//1920-1929
0x06566,0x0d4a0,0x0ea50,0x06e95,0x05ad0,0x02b60,0x186e3,0x092e0,0x1c8d7,0x0c950,//1930-1939
0x0d4a0,0x1d8a6,0x0b550,0x056a0,0x1a5b4,0x025d0,0x092d0,0x0d2b2,0x0a950,0x0b557,//1940-1949
0x06ca0,0x0b550,0x15355,0x04da0,0x0a5b0,0x14573,0x052b0,0x0a9a8,0x0e950,0x06aa0,//1950-1959
0x0aea6,0x0ab50,0x04b60,0x0aae4,0x0a570,0x05260,0x0f263,0x0d950,0x05b57,0x056a0,//1960-1969
0x096d0,0x04dd5,0x04ad0,0x0a4d0,0x0d4d4,0x0d250,0x0d558,0x0b540,0x0b6a0,0x195a6,//1970-1979

0x095b0,0x049b0,0x0a974,0x0a4b0,0x0b27a,0x06a50,0x06d40,0x0af46,0x0ab60,0x09570,//1980-1989
0x04af5,0x04970,0x064b0,0x074a3,0x0ea50,0x06b58,0x055c0,0x0ab60,0x096d5,0x092e0,//1990-1999
0x0c960,0x0d954,0x0d4a0,0x0da50,0x07552,0x056a0,0x0abb7,0x025d0,0x092d0,0x0cab5,//2000-2009
0x0a950,0x0b4a0,0x0baa4,0x0ad50,0x055d9,0x04ba0,0x0a5b0,0x15176,0x052b0,0x0a930,//2010-2019
0x07954,0x06aa0,0x0ad50,0x05b52,0x04b60,0x0a6e6,0x0a4e0,0x0d260,0x0ea65,0x0d530,//2020-2029
0x05aa0,0x076a3,0x096d0,0x04bd7,0x04ad0,0x0a4d0,0x1d0b6,0x0d250,0x0d520,0x0dd45,//2030-2039
0x0b5a0,0x056d0,0x055b2,0x049b0,0x0a577,0x0a4b0,0x0aa50,0x1b255,0x06d20,0x0ada0,//2040-2049

0x14b63,0x09370,0x049f8,0x04970,0x064b0,0x168a6,0x0ea50, 0x06b20,0x1a6c4,0x0aae0,//2050-2059
0x0a2e0,0x0d2e3,0x0c960,0x0d557,0x0d4a0,0x0da50,0x05d55,0x056a0,0x0a6d0,0x055d4,//2060-2069
0x052d0,0x0a9b8,0x0a950,0x0b4a0,0x0b6a6,0x0ad50,0x055a0,0x0aba4,0x0a5b0,0x052b0,//2070-2079
0x0b273,0x06930,0x07337,0x06aa0,0x0ad50,0x14b55,0x04b60,0x0a570,0x054e4,0x0d160,//2080-2089
0x0e968,0x0d520,0x0daa0,0x16aa6,0x056d0,0x04ae0,0x0a9d4,0x0a2d0,0x0d150,0x0f252,//2090-2099

0x0d520 //2100
解析

十六进制的数据要转成二进制解析

二进制形式

xxxx xxxx xxxx xxxx xxxx
20-17 16-13 12-9 8-5 4-1

1-4: 表示当年有无闰年,有的话,为闰月的月份,没有的话,为0。
5-16:为除了闰月外的正常月份是大月还是小月,1为30天,0为29天。
注意:从1月到12月对应的是第16位到第5位。
17-20: 表示闰月是大月还是小月,仅当存在闰月的情况下有意义。

例子1

1980年的数据是(十六进制):0x095b0
二进制:0000 1001 0101 1011 0000

0000 1001 0101 1011 0000
20-17 16-13 12-9 8-5 4-1
无意义 1-4月 5-8月 9-12月 非闰年

最右边的0000表示1980年没有闰月,所以最左边的0000也没有意义。从1月到12月的天数依次为:30、29、29、30、29、30、29、30、30、29、30、30,共12个月。分别对应16-5位的二进制数,1对30,0对29。

例子2

2017年的数据是:0x15176
二进制:0001 0101 0001 0111 0110

0001 0101 0001 0111 0110
20-17 16-13 12-9 8-5 4-1
闰大月 1-4月 5-8月 9-12月 闰六月

从1月到12月的天数依次为:29、30、29、30、29、29(六月)、30(闰六月)、29、30、29、30、30、30,共13个月。

使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
//传回农历 y年的总天数
//例如2015年农历有354天
private static int yearDays(int y) {
//348为12个月都为平月29日的年总天数
int i, sum = 348;
for (i = 0x8000; i > 0x8; i >>= 1) {
// i >>= 1 化为二进制向右移一位并赋给原值
// 循环内从16-5位内找 有1则为大月 总天数+1
if ((lunarInfo[y - 1900] & i) != 0)
sum += 1;
}
return (sum + leapDays(y));
}

//传回农历 y年闰月的天数
private static int leapDays(int y) {
if (leapMonth(y) != 0) {
if ((lunarInfo[y - 1900] & 0x10000) != 0)
//闰大月
return 30;
else
//闰小月
return 29;
} else
return 0;
}

//传回农历 y年闰哪个月 1-12 , 没闰传回 0
private static int leapMonth(int y) {
//用4-1位与“1111”进行与运算
return (int) (lunarInfo[y - 1900] & 0xf);
}

//传回农历 y年m月的总天数
private static int monthDays(int y, int m) {
if ((lunarInfo[y - 1900] & (0x10000 >> m)) == 0)
return 29;
else
return 30;
}

//传回农历 y年的生肖
public String animalsYear(int year) {
final String[] Animals = new String[]{"鼠", "牛", "虎",
"兔", "龙", "蛇","马", "羊", "猴", "鸡", "狗", "猪"};
return Animals[(year - 4) % 12];
}

日历重点是公历和阴历的转换,明后弄懂了再撰文。

转换弄懂了的话到时候结婚算八字都不用翻风水书了呢( ̄▽ ̄)

课外扩展:
八字神煞合婚算法,看看自己中了几枪