Python重写万年历引发的血案,历史少了395+10天

基姆拉尔森和蔡勒公式都只适用于1582年10月15日之后

详情见我的摘抄和链接

别人的博客

要准确回答这个问题,必须弄清公历(也称格里高利历或儒略历)于元年(不存在公元0年,元年即1年)之后的修改和纠错情况:
1、儒略历从公元前45年1月1日(罗马纪元709年11月1日)施行.1582年10月15日以前的置闰方法是每四年置一闰,即每400年置100闰.年长和现在一样,平年2月28天,全年365天;闰年2月为29天,全年366天.大概在前9年以后,为拍奥古斯都大帝的马屁,罗马元老院调整了各月的天数,使之成为现在这个样子.此后儒略历的月序和各月的天数都没再作变更,沿用至今.
1582年10月15日之后,每400年97闰,即:能被4整除的年份和能被400整除的年份均置闰,但能被100整除不能被400整除年份不置闰.如,1700、1800、1900年为平年,2000年为闰年.
2、公元4年没有置闰,该年2月仍然为28天.前45年--前9年之间,罗马掌管历法的大祭司把恺撒大帝改历令上的“每隔三年置一闰”错解成“每三年置一闰”.为纠正此错,前9年,奥古斯都大帝下令从前8年至4年停止置闰,即前5年、前1年和4年仍是平年,以后又恢复为每四年一闰(前41年应为第1个闰年,因为前45年1月1日到前42年12月31日满四年整,故应在前41年2月置闰,实际上前42年被置为闰年.前9年既是实际的闰年,也应为四年一闰的闰年.前45年~前9年期间共36年,本应置9闰,实际闰了12次).
3、16世纪下半叶,儒略历上的日期比回归年迟了10天.比如,1583年的春分应在3月21日,历法上却是3月11日.又因教会规定耶稣复活节应在春分之后第一次月圆后的第一个星期日,由于春分已相差10天之多,耶稣究竟在哪一天“复活”的,也成了问题.因此,罗马教皇格里高利十三世,于1582年采用意大利医生里利奥的方案,将1582年10月5日到14日之间的10天宣布撤销,继10月4日之后为10月15日,原有星期不变,并执行新的置闰规则.此后这一历法没再作修改,沿用至今.
由前所述可知, 1582年前后,除了置闰规则不同外, 4年2月29日和1582年10月5日至14日在公历上根本没存在过.掌握了这些知识,剩下的就是简单的运算问题了.
网上流传的可推算干支和星期的公式,大多只适用于1582年10月15日之后.大概很少有人清楚这一点,所以用“W= (y-1)+[(y-1)/4]-[(y-1)/100]+[(y-1)/400]+d”推得元年1月1日是星期一.这也是网上普遍认为元年1月1日是星期一的原因.
用w除以7,余几就是星期几.y表示公元年份,d表示所求之日在这一年中是第几天,如3月1日在平年里是第31+28+1=60天,而3月1日在闰年里是第31+29+1=61天.[.]表示取整运算,计算出来的结果是不大于方括号里面的数的最大整数,如[3.1]=3,[-1.2]=-2,[6]=6.
下面用最笨的但也是最直观的方法来计算元年1月1日是星期几:
查历书可知:2013年1月6日星期日
元年1月1日–1582年10月4日的天数=1581×365+[1581÷4](取整数,得395闰)-1(公元4年没闰)+277(1582年元旦至10月4日天数)=577736
1582年10月15日–1600年12月31日的天数=78+(18×365+5闰)=6653
1601年1月1日–2013年1月6日星期日的天数=412×365+100闰+6(2013年的6天)=150486
三项之和=577736+6653+150486=734875
734875÷7 =104982+1/7 即余数=1
注意了:2013年1月6日是星期日,从星期日、星期六、星期五……星期一、星期日……这样倒排、倒推至元年1月1日,余数为1,说明元年1月1日处在倒排的第一个位置(顺排则是第七位),正是星期日,而不是星期一.
如果以上所述历法知识没有遗漏天数、时日的话,则可以肯定元年1月1日是星期日.

总结,1582年以前,置闰规则有点乱,1582年10月4日结束,直接开始10月15日

所以,写万年历你还只能套公式,算日期是不可能准的

基姆拉尔森公式:W= (d+2*m+3*(m+1)/5+y+y/4-y/100+y/400) mod 7

蔡勒公式:W = [C/4] - 2C + y + [y/4] + [13 * (M+1) / 5] + d - 1,对于W >0则W = W%7,否则W = ( W % 7 + 7 ) % 7;

#万年历小程序
#以前C语言写过,用Python再来一次

"""
分析:程序要求输入年份和月份,打印出当月的日历
只适用于1582年之后

判断闰年函数
判断月份有多少天函数
判断某年某月第一天是周几函数
格式化打印输出函数
"""

def is_leep_year(year): #判断闰年
    #能被400整除 或 能被4整除但不能被100整除
    if year%400==0 or (year%4==0 and year%100!=0):
        return True
    else:
        return False

def many_day_ofmonth(year,month):   #判断某月有多少天
    if month in (1,3,5,7,8,10,12):
        return 31
    elif month in (4,6,9,11):
        return 30
    else:
        if is_leep_year(year):
            return 29
        else:
            return 28

def what_Week(year,month):   #判断某年某月一日是周几
    #思路,算出距离公元1月1日的天数,对7取模,据说当天是周一
    #这个思路是错误的,因为1582年以前每400年置100闰年,而且历史少了10天
    #当时用C写好像是套的公式。。还用公式吧,稳
    n = int((1+2*month+3*(month+1)/5+year+year/4-year/100+year/400)%7)
    return n

def print_This_month(year,month):
    print("*"*50)
    print("\t\t\t\t\t{0}年\t{1}月".format(year,month))
    print("周日 \t周一 \t周二 \t周三 \t周四 \t周五 \t周六")
    day = many_day_ofmonth(year,month)
    week = what_Week(year,month)
    print('\t\t'*week,end='')
    n = week
    for i in range(1,day+1):
        print("{}\t\t".format(i),end='')
        n += 1
        if n%7 == 0:
            print('')
    print(week)



#主函数......
year = int(input("请输入年份:"))
month = int(input("请输入月份:"))
print_This_month(year,month)

你可能感兴趣的:(Python)