《算法的乐趣》11.算法与历法-------python

格里历(公历)生成算法

格里历的历法规则

分为平常年和闰年:
1.如果年份是4的倍数,且不是100的倍数,则是闰年;
2.如果年份是400的倍数,则是闰年;
3.不满足1.2条件的就是平常年。

def is_leap_year(year):
    if (year % 4 == 0 and year % 100 != 0) or (year % 400) == 0:
        return '%d年是闰年' % year
    else:
        return '%d年不是闰年' % year

for year in range(1995, 2020):
    print(is_leap_year(year))
1995年不是闰年
1996年是闰年
1997年不是闰年
1998年不是闰年
1999年不是闰年
2000年是闰年
2001年不是闰年
2002年不是闰年
2003年不是闰年
2004年是闰年
2005年不是闰年
2006年不是闰年
2007年不是闰年
2008年是闰年
2009年不是闰年
2010年不是闰年
2011年不是闰年
2012年是闰年
2013年不是闰年
2014年不是闰年
2015年不是闰年
2016年是闰年
2017年不是闰年
2018年不是闰年
2019年不是闰年
今天星期几
直接根据日期的差值

两个日期之间相隔的天数分为三个部分:
前一个日期所在年份还剩下的天数+两个日期之间相隔的整数年包含的天数+后一个日期所在的年过去的天数
对7取余数

def is_leap_year(year):
    """是否是闰年"""
    if (year % 4 == 0 and year % 100 != 0) or (year % 400) == 0:
        return 1
    else:
        return 0

def pass_day(day):
    """一年过去了多少天"""
    days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
    passday = day[2]
    if is_leap_year(day[0]):
        days[1] = 29
    i = 0
    while i < day[1] - 1:
        passday += days[i]
        i += 1
    return passday

def what_day(day1, day2):
    """今天星期几"""
    day1 = [int(i) for i in day1.split('-')]
    day2 = [int(i) for i in day2.split('-')]
    sumday = 0
    # 中间相隔的年数
    middle_year = day1[0] + 1 
    while middle_year < day2[0]:
        if is_leap_year(middle_year):
            sumday += 366
        else:
            sumday += 365
        middle_year += 1
    # 前一个日期还剩下的天数
    if is_leap_year(day1[0]):
        sumday += 366 - pass_day(day1)
    else:
        sumday += 365 - pass_day(day1)
    # 后一个日期过去的天数
    sumday += pass_day(day2)

    return (sumday % 7)
    

print(what_day('1977-3-27', '2005-5-31'))
2
利用儒略历计算日期的差值

儒略日(Julian Day,JD):从公元前4713年1月1日UTC12:00开始所经过的天数。这天对应的是星期一。
J D = ⌊ 153 m + 2 5 ⌋ + 365 y + ⌊ y 4 ⌋ − ⌊ y 100 ⌋ + ⌊ y 400 ⌋ + d a y − 32045 JD = \lfloor \frac{153m+2}{5} \rfloor +365y + \lfloor \frac{y}{4} \rfloor - \lfloor \frac{y}{100} \rfloor + \lfloor \frac{y}{400} \rfloor + day - 32045 JD=5153m+2+365y+4y100y+400y+day32045
其中:
a = ⌊ 14 − m o n t h 12 ⌋ a = \lfloor \frac{14-month}{12} \rfloor a=1214month
y = y e a r + 4800 − a y = year + 4800 - a y=year+4800a
m = m o n t h + 12 a − 3 m = month + 12a -3 m=month+12a3
其中 y e a r , m o n t h , d a y year,month,day year,month,day分别代表年份,月份和日期。

def JD(day):
    """今天星期几"""
    day = [int(i) for i in day.split('-')]
    year = day[0]
    month = day[1]
    day = day[2]
    a = int((14 - month)/12)
    y = year + 4800 - a
    m = month + 12*a -3
    return int((153*m+2)/5) + 365*y + int(y/4) - int(y/100) + int(y/400) + day - 32045 

day1 = JD('1977-3-27')
day2 = JD('2005-5-31')
difference = day2 - day1
print(difference%7)
2
利用蔡勒公式计算星期数

公元前1年的12月31日是星期日,作为标准日期,来对日期进行推导:
w = ( ( y e a r − 1 ) × 365 + ⌊ y 4 ⌋ − ⌊ y 100 ⌋ + ⌊ y 400 ⌋ + D ) % 7 w=((year-1)×365 + \lfloor \frac{y}{4} \rfloor - \lfloor \frac{y}{100} \rfloor + \lfloor \frac{y}{400} \rfloor + D)\%7 w=((year1)×365+4y100y+400y+D)%7
其中:
y e a r year year为年份, D D D为已经过去的天数。

def is_leap_year(year):
    """是否是闰年"""
    if (year % 4 == 0 and year % 100 != 0) or (year % 400) == 0:
        return 1
    else:
        return 0

def pass_day(day):
    """一年过去了多少天"""
    days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
    passday = day[2]
    if is_leap_year(day[0]):
        days[1] = 29
    i = 0
    while i < day[1] - 1:
        passday += days[i]
        i += 1
    return passday

def what_day(day):
    day = [int(i) for i in day.split('-')]
    d = day[0] - 1 
    return (d*365+int(d/4)-int(d/100)+int(d/400)+pass_day(day))%7

print(what_day("2005-5-31"))
2

蔡勒公式:
w = ( y + ⌊ y 4 ⌋ + ⌊ c 4 ⌋ − 2 c + ⌊ 13 ( m + 1 ) 5 ⌋ + d − 1 ) % 7 w = (y+\lfloor \frac{y}{4} \rfloor + \lfloor \frac{c}{4} \rfloor - 2c + \lfloor \frac{13(m+1)}{5} \rfloor + d - 1)\%7 w=(y+4y+4c2c+513(m+1)+d1)%7
其中:
c c c:世纪数减一的值
m m m:月数,大于等于3,小于等于14,一月和二月看做上一年的13月和14月
y y y:年份,取后两位
d d d:某月内的日数

def zeller(day):
    day = [int(i) for i in day.split('-')]
    # c
    c = day[0] // 100
    # m
    if day[1] < 3:
        m = day[1] + 12
    else: 
        m = day[1]
    # y
    y = day[0] % 100
    # d
    d = day[2]
    return (y + int(y/4) + int(c/4) - 2*c + int(13*(m+1)/5) + d - 1) % 7

print(zeller('2005-5-31'))
2
生成日历的算法
def is_leap_year(year):
    """是否是闰年"""
    if (year % 4 == 0 and year % 100 != 0) or (year % 400) == 0:
        return 1
    else:
        return 0

def zeller(year, month, day):
    # c
    c = year // 100
    # m
    if month < 3:
        m = month + 12
    else: 
        m = month
    # y
    y = year % 100
    # d
    d = day
    return (y + int(y/4) + int(c/4) - 2*c + int(13*(m+1)/5) + d - 1) % 7


# 月份的天数
def month_day(year, month):
    days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
    if is_leap_year(year):
        days[1] = 29
    day = days[month-1]
    return day

def print_month_calendar(year, month):
    days = month_day(year, month)
    week = zeller(year, month, 1)
    print('======================%d年%d月======================' % (year, month))
    print("日\t一\t二\t三\t四\t五\t六")
    i = 1
    while i <= days:
        print(i,'\t', end='')
        if week == 6:
            print('\n')
        i += 1
        week = (week+1) % 7
    print('\n')

if __name__ == "__main__":
    for i in range(1, 13):
        print_month_calendar(2019, i) 
======================2019年1月======================
日	一	二	三	四	五	六
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 	

======================2019年2月======================
日	一	二	三	四	五	六
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 	

======================2019年3月======================
日	一	二	三	四	五	六
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 	

======================2019年4月======================
日	一	二	三	四	五	六
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 	

======================2019年5月======================
日	一	二	三	四	五	六
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 	

======================2019年6月======================
日	一	二	三	四	五	六
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 	

======================2019年7月======================
日	一	二	三	四	五	六
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 	

======================2019年8月======================
日	一	二	三	四	五	六
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 	



======================2019年9月======================
日	一	二	三	四	五	六
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 	

======================2019年10月======================
日	一	二	三	四	五	六
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 	

======================2019年11月======================
日	一	二	三	四	五	六
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 	



======================2019年12月======================
日	一	二	三	四	五	六
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 	

二十四节气的天文学计算

二十四节气的起源

二十四节气起源于中国黄河流域。远在春秋时代,g古人就开始使用仲春、仲夏、仲秋和仲冬四个节气指导农耕种植。后来经过不断地改进与完善,到秦汉年间,二十四节气已经基本确立。
公元前104年(汉武帝太初元年),汉武帝颁布由邓平等人制定的《太初历》正式把二十四节气订于历法,明确了二十四节气的天文位置。
二十四节气天文位置的定义,就是从太阳黄经零度开始,沿黄经每运行15度所经历的时日称为一个节气。太阳一个回归年运行360度,共经历二十四个节气,每个公历月对应两个节气。
其中,每月第一个节气为“节令”,即立春、惊蛰、清明、立夏、芒种、小暑、立秋、白露、寒露、立冬、大雪和小寒十二个节令;
每月的第二个节气为“中气”,即雨水、春分、谷雨、小满、夏至、大暑、处暑、秋分、霜降、小雪、冬至和大寒十二个中气。
“节令”和“中气”交替出现,各历时15天,人们习惯上把“节令”和“中气”统称为“节气”。

二十四节气的天文学定义

补充补充天文学知识

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值