Abo

中国农历日期的算法(gregorian date)

主要就是节气积日公式跟朔日的计算


6_29

放在前面:公历就是阳历,农历就是阴历。

前言

按照我们平常的经验,当我们打开一本日历,我们经常使用的公历和中国传统使用的农历总是会有一定的差距。

比如2019.11.01所对应的农历时间是十月初五

2020.11.01所应的农历日期是九月十六

为什么会出现这样的差距?

公历

我们所知道的最基础的概念就是一年有365天,但实际上从天文的角度上来看,一年的实际概念是地球绕太阳一周的时间,这个时间应该是365.2422天,如果我们一直用365天作为一年的话,那么长久过后,0.2422可能会造成很大误差。

每四年积累起来的路程可以近似让他再走个1天,即平均每四年会出一个闰年,或者说每四年会多一个二月二十九号,然而平均每四年补一天的方法也会造成误差,因为0.2422*4=0.9688,然后我们补一天会导致往前面偏移一点点,这个误差积累到100年的时候会多出一天,然后积累到 400年的时候又应该补回一个闰年 所以我们算法是:平均每四年算一次闰年,100年的时候不算即是-1天。400年的时候补回一个闰年

比如说2020是闰年,一直到2100年我们不认为它不是闰年

农历

比如春节,可能出现在公历1月,也可能出现在公历2月,但是放在农历都是正月初一,相比公历,农历的定义为月球绕地球的一圈

规定:

满月为每个月的十五——古时称之为

空月(看不见月亮)为每个月的初一——古时称之为

当月球从看不到到满月再回到看不到的状态,这样的一个过程我们称为朔望月:29.53天,古人把这个时间称为一个月,一年有十二个月,则农历时间的一年:29.52*12=354.36(天)

相比阳历:365.2422-354.36=10.8822

那要怎么弥补之间的空缺,古人算出最好的比例:19年补7个月,称闰月

365.2422*19=6939.6018

29.531219 + 7 * 29.53 = 6939.55

通过观测跟计算分配29天跟30天于各个月份,此为不均匀分配的

二十四节气

20191028192822

360度/15度 = 24
因为是根据地球绕太阳来分的,所以二十四节气是一种阳历,所以说清明节是在每年的4.5,而不是在农历的4.5,

24节气分为2类:一类叫节气,一类叫中气,隔着来排列

农历中:正月前有腊月,农历一月称正月,十一月称冬月,十二月称腊月

农历里每一个月有且对应一个中气

比如2019年正月时间为:2月5日-3月6日,说明根据天文观测,2月5日这一天刚好看不到月亮,然后3月6日刚好回到看不到的状态。

只要满足 每一个月都包含一个中气的情况,就不会出现闰月

当发生闰月情况下,会有不包含中气的情况,比如2020年中有

四月 4.23-5.22
空月(润四月) 5.23-6.20
五月 6.21-7.20因为夏至一定要对应五月,则会导致出现空月的情况

当找不到一个中气跟其对应的时候,我们称之为闰月

节气积日公式

1
2
3
4
5
6
import math
def F(y,x):
return 365.242 * (y - 1900) + 6.2 + 15.22 * x - 1.9 * sin(0.262 * x)
F(1900,1) //20.9278,说明1900第二个节气,120号是大寒
F(1900,2) //35.6893
F(1900,3) //50.5156

实现函数转化成正确的公历日期:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import math
def F(y,x):
return 365.242 * (y - 1900) + 6.2 + 15.22 * x - 1.9 * sin(0.262 * x)
days_in_month = [31,28,31,30,31,....]
def days_to_gregorian_date(n):
"""
:param n: num days from 1900-01-00
"""
m = 0
while n > days_in_mmonth[m]:
n = n - days_in_nmonth[m]
m = (m + 1) % 12
month = m + 1
day = n
return month,day

// 测试
m,d = days_to_gregorian_date(10) //110号 如果传50 则为219
print("{}月{}日",format(m,d))

for i in range(0,4):
days = int(F(1900,i))
m,d = days_to_gregorian_date(days)
print("{}月{}日",format(m,d))

输入2015,发现结果不匹配 ,其实是上边代码的2月份不能一直考虑为28天,因为有闰年夹杂在中间

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
def F(y,x):
return 365.242 * (y - 1900) + 6.2 + 15.22 * x - 1.9 * math.sin(0.262 * x)

def is_leap_year(year):
if year % 400 == 0
return true
elif year % 100 == 0
return false
elif yeaar % 4 == 0
return true
else:
return false

def get_days_in_month(year,month):
if is_leap_year(year) and mouth == 1: //如果为闰年,且所求为2
return days_in_month[month] + 1
else
return days_in_month[month]

def days_to_gregorian_date(n):
"""
:param n: num days from 1900-01-00
"""
m = 0
year = 1900
while n > get_days_in_month(y,m):
n = n - get_days_in_month(y,m)
m = (m + 1) % 12
if m == 0:
y = y + 1
year = y
month = m + 1
day = n
return year,month,day
for i in range(0,4):
days = int(F(2015,i))
y,m,d = days_to_gregorian_date(days)
print("{}年{}月{}日",format(y,m,d))

由此可以算出中气,节气

0 腊月

1 正月

朔日计算公式

计算第m个朔日的时间

1
2
3
4
5
6
def M(m):
return 1.6 + 29.5306 * m + 0.4 * math.sin(1 - 0.45058 * m)
for i in range(0,4):
days = int(M(i)) //求1900年的前面四个朔日时间
y,m,d = days_to_gregorian_date(days)
print("{}年{}月{}日",format(y,m,d))

综合性算法

1

2

求距1900-01-00过了多少天

3

求离当前时间最近的朔日

例:比如我想求2019年3月12日对应的农历日期

4

  1. 首先利用gregorian_date_to_days 得到当前天数
  2. 再利用get_nearest_shuo_day得到最近朔日点

6

计算出离当前时间最近的朔日点,然后days减去初一(朔日点)则可以得到农历时间几月几号

  1. 定月份(通过24节气来确定月份)

7

8

8.5

9

通过识别月份包裹哪个二十四节气的day数字,由此来判断农历月份

更为标准的写法(js)

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
/**
* 农历1900-2100的润大小信息表
* @Array Of Property
* @return Hex
*
* 5位16进制数代表20位2进制
* 比如1900年代表0x04bd8二进制
* 0000 0100 1011 1101 1000
* 其中0-3位代表此年的闰月是大月还是小月,1为大月30天,0为小月29天
* 4-15位代表1-12月每个月是大月还是小月,1为大月30天,0为小月29天
* 16-20位代表此年是否闰月,如果全0代表不闰月,否则代表润的月份
*/
lunarInfo: [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, 0x04afb, 0x04ad0, 0x0a4d0, 0x1d0b6, 0x0d250, 0x0d520, 0x0dd45, //2030-2039
0x0b5a0, 0x056d0, 0x055b2, 0x049b0, 0x0a577, 0x0a4b0, 0x0aa50, 0x1b255, 0x06d20, 0x0ada0, //2040-2049
/**Add By JJonline@JJonline.Cn**/
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

比如说 0x055d2 表示1909年有个闰二月,有 29天, 中间 55D 则 代表 0101 0101 1101,12个位正好代表12个月,第11位跟第12位我们称之为冬月跟腊月,0代表29天,1代表30天

所以1月29天,2月30天,闰二月29天。。。

(其实我们农历一般不说年份),从1909公历一月 开始看,农历对应是从腊月初十开始到腊月三十,然后正月廿九,二月三十,闰二月廿九,三月廿九……

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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
/**
* 1900-2100各年的24节气日期速查表
* @Array Of Property
* @return 0x string For splice
*/
sTermInfo:['9778397bd097c36b0b6fc9274c91aa','97b6b97bd19801ec9210c965cc920e','97bcf97c3598082c95f8c965cc920f',
'97bd0b06bdb0722c965ce1cfcc920f','b027097bd097c36b0b6fc9274c91aa','97b6b97bd19801ec9210c965cc920e',
'97bcf97c359801ec95f8c965cc920f','97bd0b06bdb0722c965ce1cfcc920f','b027097bd097c36b0b6fc9274c91aa',
'97b6b97bd19801ec9210c965cc920e','97bcf97c359801ec95f8c965cc920f','97bd0b06bdb0722c965ce1cfcc920f',
'b027097bd097c36b0b6fc9274c91aa','9778397bd19801ec9210c965cc920e','97b6b97bd19801ec95f8c965cc920f',
'97bd09801d98082c95f8e1cfcc920f','97bd097bd097c36b0b6fc9210c8dc2','9778397bd197c36c9210c9274c91aa',
'97b6b97bd19801ec95f8c965cc920e','97bd09801d98082c95f8e1cfcc920f','97bd097bd097c36b0b6fc9210c8dc2',
'9778397bd097c36c9210c9274c91aa','97b6b97bd19801ec95f8c965cc920e','97bcf97c3598082c95f8e1cfcc920f',
'97bd097bd097c36b0b6fc9210c8dc2','9778397bd097c36c9210c9274c91aa','97b6b97bd19801ec9210c965cc920e',
'97bcf97c3598082c95f8c965cc920f','97bd097bd097c35b0b6fc920fb0722','9778397bd097c36b0b6fc9274c91aa',
'97b6b97bd19801ec9210c965cc920e','97bcf97c3598082c95f8c965cc920f','97bd097bd097c35b0b6fc920fb0722',
'9778397bd097c36b0b6fc9274c91aa','97b6b97bd19801ec9210c965cc920e','97bcf97c359801ec95f8c965cc920f',
'97bd097bd097c35b0b6fc920fb0722','9778397bd097c36b0b6fc9274c91aa','97b6b97bd19801ec9210c965cc920e',
'97bcf97c359801ec95f8c965cc920f','97bd097bd097c35b0b6fc920fb0722','9778397bd097c36b0b6fc9274c91aa',
'97b6b97bd19801ec9210c965cc920e','97bcf97c359801ec95f8c965cc920f','97bd097bd07f595b0b6fc920fb0722',
'9778397bd097c36b0b6fc9210c8dc2','9778397bd19801ec9210c9274c920e','97b6b97bd19801ec95f8c965cc920f',
'97bd07f5307f595b0b0bc920fb0722','7f0e397bd097c36b0b6fc9210c8dc2','9778397bd097c36c9210c9274c920e',
'97b6b97bd19801ec95f8c965cc920f','97bd07f5307f595b0b0bc920fb0722','7f0e397bd097c36b0b6fc9210c8dc2',
'9778397bd097c36c9210c9274c91aa','97b6b97bd19801ec9210c965cc920e','97bd07f1487f595b0b0bc920fb0722',
'7f0e397bd097c36b0b6fc9210c8dc2','9778397bd097c36b0b6fc9274c91aa','97b6b97bd19801ec9210c965cc920e',
'97bcf7f1487f595b0b0bb0b6fb0722','7f0e397bd097c35b0b6fc920fb0722','9778397bd097c36b0b6fc9274c91aa',
'97b6b97bd19801ec9210c965cc920e','97bcf7f1487f595b0b0bb0b6fb0722','7f0e397bd097c35b0b6fc920fb0722',
'9778397bd097c36b0b6fc9274c91aa','97b6b97bd19801ec9210c965cc920e','97bcf7f1487f531b0b0bb0b6fb0722',
'7f0e397bd097c35b0b6fc920fb0722','9778397bd097c36b0b6fc9274c91aa','97b6b97bd19801ec9210c965cc920e',
'97bcf7f1487f531b0b0bb0b6fb0722','7f0e397bd07f595b0b6fc920fb0722','9778397bd097c36b0b6fc9274c91aa',
'97b6b97bd19801ec9210c9274c920e','97bcf7f0e47f531b0b0bb0b6fb0722','7f0e397bd07f595b0b0bc920fb0722',
'9778397bd097c36b0b6fc9210c91aa','97b6b97bd197c36c9210c9274c920e','97bcf7f0e47f531b0b0bb0b6fb0722',
'7f0e397bd07f595b0b0bc920fb0722','9778397bd097c36b0b6fc9210c8dc2','9778397bd097c36c9210c9274c920e',
'97b6b7f0e47f531b0723b0b6fb0722','7f0e37f5307f595b0b0bc920fb0722','7f0e397bd097c36b0b6fc9210c8dc2',
'9778397bd097c36b0b70c9274c91aa','97b6b7f0e47f531b0723b0b6fb0721','7f0e37f1487f595b0b0bb0b6fb0722',
'7f0e397bd097c35b0b6fc9210c8dc2','9778397bd097c36b0b6fc9274c91aa','97b6b7f0e47f531b0723b0b6fb0721',
'7f0e27f1487f595b0b0bb0b6fb0722','7f0e397bd097c35b0b6fc920fb0722','9778397bd097c36b0b6fc9274c91aa',
'97b6b7f0e47f531b0723b0b6fb0721','7f0e27f1487f531b0b0bb0b6fb0722','7f0e397bd097c35b0b6fc920fb0722',
'9778397bd097c36b0b6fc9274c91aa','97b6b7f0e47f531b0723b0b6fb0721','7f0e27f1487f531b0b0bb0b6fb0722',
'7f0e397bd097c35b0b6fc920fb0722','9778397bd097c36b0b6fc9274c91aa','97b6b7f0e47f531b0723b0b6fb0721',
'7f0e27f1487f531b0b0bb0b6fb0722','7f0e397bd07f595b0b0bc920fb0722','9778397bd097c36b0b6fc9274c91aa',
'97b6b7f0e47f531b0723b0787b0721','7f0e27f0e47f531b0b0bb0b6fb0722','7f0e397bd07f595b0b0bc920fb0722',
'9778397bd097c36b0b6fc9210c91aa','97b6b7f0e47f149b0723b0787b0721','7f0e27f0e47f531b0723b0b6fb0722',
'7f0e397bd07f595b0b0bc920fb0722','9778397bd097c36b0b6fc9210c8dc2','977837f0e37f149b0723b0787b0721',
'7f07e7f0e47f531b0723b0b6fb0722','7f0e37f5307f595b0b0bc920fb0722','7f0e397bd097c35b0b6fc9210c8dc2',
'977837f0e37f14998082b0787b0721','7f07e7f0e47f531b0723b0b6fb0721','7f0e37f1487f595b0b0bb0b6fb0722',
'7f0e397bd097c35b0b6fc9210c8dc2','977837f0e37f14998082b0787b06bd','7f07e7f0e47f531b0723b0b6fb0721',
'7f0e27f1487f531b0b0bb0b6fb0722','7f0e397bd097c35b0b6fc920fb0722','977837f0e37f14998082b0787b06bd',
'7f07e7f0e47f531b0723b0b6fb0721','7f0e27f1487f531b0b0bb0b6fb0722','7f0e397bd097c35b0b6fc920fb0722',
'977837f0e37f14998082b0787b06bd','7f07e7f0e47f531b0723b0b6fb0721','7f0e27f1487f531b0b0bb0b6fb0722',
'7f0e397bd07f595b0b0bc920fb0722','977837f0e37f14998082b0787b06bd','7f07e7f0e47f531b0723b0b6fb0721',
'7f0e27f1487f531b0b0bb0b6fb0722','7f0e397bd07f595b0b0bc920fb0722','977837f0e37f14998082b0787b06bd',
'7f07e7f0e47f149b0723b0787b0721','7f0e27f0e47f531b0b0bb0b6fb0722','7f0e397bd07f595b0b0bc920fb0722',
'977837f0e37f14998082b0723b06bd','7f07e7f0e37f149b0723b0787b0721','7f0e27f0e47f531b0723b0b6fb0722',
'7f0e397bd07f595b0b0bc920fb0722','977837f0e37f14898082b0723b02d5','7ec967f0e37f14998082b0787b0721',
'7f07e7f0e47f531b0723b0b6fb0722','7f0e37f1487f595b0b0bb0b6fb0722','7f0e37f0e37f14898082b0723b02d5',
'7ec967f0e37f14998082b0787b0721','7f07e7f0e47f531b0723b0b6fb0722','7f0e37f1487f531b0b0bb0b6fb0722',
'7f0e37f0e37f14898082b0723b02d5','7ec967f0e37f14998082b0787b06bd','7f07e7f0e47f531b0723b0b6fb0721',
'7f0e37f1487f531b0b0bb0b6fb0722','7f0e37f0e37f14898082b072297c35','7ec967f0e37f14998082b0787b06bd',
'7f07e7f0e47f531b0723b0b6fb0721','7f0e27f1487f531b0b0bb0b6fb0722','7f0e37f0e37f14898082b072297c35',
'7ec967f0e37f14998082b0787b06bd','7f07e7f0e47f531b0723b0b6fb0721','7f0e27f1487f531b0b0bb0b6fb0722',
'7f0e37f0e366aa89801eb072297c35','7ec967f0e37f14998082b0787b06bd','7f07e7f0e47f149b0723b0787b0721',
'7f0e27f1487f531b0b0bb0b6fb0722','7f0e37f0e366aa89801eb072297c35','7ec967f0e37f14998082b0723b06bd',
'7f07e7f0e47f149b0723b0787b0721','7f0e27f0e47f531b0723b0b6fb0722','7f0e37f0e366aa89801eb072297c35',
'7ec967f0e37f14998082b0723b06bd','7f07e7f0e37f14998083b0787b0721','7f0e27f0e47f531b0723b0b6fb0722',
'7f0e37f0e366aa89801eb072297c35','7ec967f0e37f14898082b0723b02d5','7f07e7f0e37f14998082b0787b0721',
'7f07e7f0e47f531b0723b0b6fb0722','7f0e36665b66aa89801e9808297c35','665f67f0e37f14898082b0723b02d5',
'7ec967f0e37f14998082b0787b0721','7f07e7f0e47f531b0723b0b6fb0722','7f0e36665b66a449801e9808297c35',
'665f67f0e37f14898082b0723b02d5','7ec967f0e37f14998082b0787b06bd','7f07e7f0e47f531b0723b0b6fb0721',
'7f0e36665b66a449801e9808297c35','665f67f0e37f14898082b072297c35','7ec967f0e37f14998082b0787b06bd',
'7f07e7f0e47f531b0723b0b6fb0721','7f0e26665b66a449801e9808297c35','665f67f0e37f1489801eb072297c35',
'7ec967f0e37f14998082b0787b06bd','7f07e7f0e47f531b0723b0b6fb0721','7f0e27f1487f531b0b0bb0b6fb0722'],

拿1900做例子:9778397bd097c36b0b6fc9274c91aa

五个为一组:

97783
97bd0
97c36
b0b6f
c9274
c91aa

转化为十进制

比如 97783,十进制为 620419(在控制台输入0x97783可以快速得到)

然后按照1:2:1:2的拆分,得到6 20 4 19,说明为正月6号,二月20号,三月4号,四月19号