爱技术 & 爱分享
爱蛋蛋 & 爱生活

闰年

今天来聊一下闰年这个东西,记得最开始学编程的时候,就有个题是 写个程序判断给定的年份是否是闰年…

闰年是比普通年分多出一段时间的年分,在各种历法中都有出现,目的是为了弥补人为规定的纪年与地球公转产生的差异。

目前使用的格里高利历闰年规则如下:

  • 公元年分除以400可整除但除以3200不可整除,为闰年。
  • 公元年分除以4可整除但除以100不可整除,为闰年。
  • 公元年分除以4不可整除,为平年。
  • 公元年分除以100可整除但除以400不可整除,为平年。
  • 公元年分除以3200可整除,为平年。

每逢闰年,2月分有29日,平年的2月分为28日。

计算方法

if ((公元年分是400的倍数)或(公元年分是4的倍数但不是100的倍数))
{
  //闰年
} else
{
  //平年
}

产生原因

通常的解释是说一年有多少天多少小时多少分,取整数365还有多余的,累积达到一天24小时后,就多加一天的年是闰年。这个解释只是告诉了大家怎么计算,是人为设置的东西。

最根本的原因是:地球绕太阳运行周期为3655小时4846秒(合365.24219天)即一回归年(tropical year)。

公历的平年只有365日,比回归年短约0.2422 日,所余下的时间约为每四年累计一天,故第四年于2月末加1天(即2月29日),使当年的历年长度为366日,这一年就为闰年(1-12月分别为31天,29天,31天,30天,31天,30天,31天,31天,30天,31天,30天,31天)。

现行公历中每400年有97个闰年。按照每四年一个闰年计算,平均每年就要多算出0.0078天,这样经过四百年就会多算出大约3天来。因此每四百年中要减少三个闰年。所以公历规定:年份是整百数时,必须是400的倍数才是闰年;不是400的倍数的世纪年,即使是4的倍数也不是闰年。

因此,1977年为平年,1980年逢4的倍数为闰年,1900年逢100的倍数但非400的倍数故为平年,2000年逢400的倍数又为闰年。

需要注意的是,公历是根据罗马人的”儒略历”改编而得。由于当时没有了解到每年要多算出0.0078天的问题,从公元前46年,到16世纪,一共累计多出了10天。为此,当时的教皇格列高利十三世,将1582年10月5日人为规定为10月15日。并开始了新闰年规定。

此外,如依照现有太阳年的长度与上述闰年规则,由于地球的自转速度逐渐降低,而公转速度则相对更加稳定,所以上述的系统经过更长的周期也会发生微小的误差。每8000年又约差一日,因此约翰·赫歇尔(John Herschel)提议每逢4000的倍数不闰,如公元4000年。但距此年分来临尚有约二千年之遥,因此还未曾真正纳入规则或实施过。又由于地球公转速度的不稳定与众多影响因素,届时是否需要纳入此规则有待商榷。

公元前的闰年

公元前之闰年出现在前1, 前5, 前9, 前13, ...,或记作1 BC,5 BC,9 BC,13 BC,...,或在数轴上记作0,-4,-8,-12,...。

判断是否闰年,须将年份值减1再以“除以4”计算,或以数轴记法表示时直接计算(正负性不影响是否整除)。

(因为没有公元0年这一年(除非临时约定,并注明对应等式),所以公元前1, 2, 3, 4, … 年应该在数学数轴上对应着(但不是,或不应该在历法上称)公元0, -1, -2, -3, … 年,而公元前1, 5, 9, 13, … 年在数学数轴上对应着0, -4, -8, -12, … 年,为4的倍数)。 记住:临时约定的数学“0”年,等于天文学固有的“0”年,等于历法公元前一年。

公元0年

阳历中的“闰年”

阳历中有闰日的年分叫闰年,相反就是平年,平年为365天,闰年为366天。在公历儒略历及纪年中,平年的二月为28天,闰年的二月为29天。闰年平月2月29日为闰日。

1950-2050年间的闰年:

1952,1956,1960,1964,1968,1972,1976,1980,1984,1988,1992,1996,2000
,2004,2008,2012,2016,2020,2024,2028,2032,2036,2040,2044,2048.

中国农历的“闰年”

中国旧历农历作为阴阳历的一种,每月的天数依照月亏而定,一年的时间以12个月为基准,平年比一回归年少约11天。

为了合上地球围绕太阳运行周期即回归年,每隔2到4年,增加一个月,增加的这个月为闰月。有闰月的一年称为闰年一年13个月。闰月加到哪个月,以农历历法规则推断,主要依照与农历的二十四节气相符合来确定。

一般年分为12个月,353(罕见)或354(多见)或355(少见)天,闰年则为13个月,383(少见)或384(多见)或385(罕见)天。

如1984年鼠年的农历中,有两个十月,通常成为前十月和后十月(即闰月)。农历闰年闰月的推算,3年一闰,5年二闰,19年七闰;农历基本上19年为一周期对应于公历同一时间。如公历的2001年5月27日、1982年5月27日和1963年5月27日这个日子,都是闰四月初五。

超长农历年

最长的农历闰月年份的天数可长达385天,这样的农历闰月年份是很罕见的。从公元前221年至公元1900年的2120年里,一共只有9次。

从公元1900年至公元4000年这2100年里出现了22次,出现的年份有1925年、1944年、2006年、2270年、2289年、2351年、2606年、2625年、2634年、2889年、2951年、2970年、3234年、3253年、3296年、3315年、3589年、3608年、3872年、3915年、3934年、3953年。平年超短农历年只有353天,公示元年至公元5000年之间,农历年有353天的年份只有以下9个:
780年、1620年、1965年、2372年、3620年、3903年、3965年、4186年、4248年。

公历1982年至2042年与农历闰年闰月对照表:

1982年5月23日 闰四月小 壬戊年 2014年10月24日 闰九月小 甲午年
1984年11月23日 闰十月小 甲子年 2017年7月23日 闰六月大 丁酉年
1987年7月26日 闰六月小 丁卯年 2020年5月23日 闰四月小 庚子年
1990年6月23日 闰五月小 庚午年 2023年3月22日 闰二月小 癸卯年
1993年4月22日 闰三月小 癸酉年 2025年7月25日 闰六月小 乙巳年
1995年9月25日 闰八月小 乙亥年 2028年6月23日 闰五月小 戊申年
1998年6月24日 闰五月小 戊寅年 2031年4月22日 闰三月小 辛亥年
2001年5月23日 闰四月小 辛巳年 2033年8月25日 闰冬月小 癸丑年
2004年3月21日 闰二月小 甲申年 2036年7月23日 闰六月大 丙辰年
2006年8月24日 闰七月小 丙戊年 2039年6月22日 闰五月小 己未年
2009年6月23日 闰五月小 己丑年 2042年3月22日 闰二月小 壬戊年
2012年5月21日 闰四月小 壬辰年

附部分语言闰年判断:

C/C++:

if ((year % 100 != 0) && (year % 4 == 0) || (year % 400 == 0)) {
   // 闰年;
} else {
   // 平年;
}
#define ISLEAP(yr) ((!((yr) % 4) && (yr) % 100) || !((yr) % 400))

C#语言:

/// <summary>
/// 判断指定年份是否为闰年
/// </summary>
/// <param name="year">年份</param>
/// <returns>返回布尔值true为闰年,反之不是</returns>
public static bool isLeapYear(int year)
{
return ((year % 4 == 0 && year % 100 != 0) ||year%400==0);
}

Java语言:

import java.util.Scanner;
public class LeapYear {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        System.out.print("请输入年份:");
        int year = input.nextInt();

        if((year % 4 == 0 && year % 100 != 0) || year % 400 ==0)
            System.out.print(year + "年是闰年。");
        else 
            System.out.print(year + "年不是闰年。");
    }
}

Python 语言:

# -*- coding: cp936 -*-
temp = input("输入年份:")
YEAR = int(temp)
if (YEAR % 4 == 0 and YEAR % 100 != 0) or YEAR % 400 == 0:    
    print ("闰年")
else:
    print ("非闰年")

C++语言:

#include<iostream>
int main()
{
    int year;
    std::cout<<"请输入年份:";
    std::cin>>year;             //输入待判断年份,如2008
    std::cout<<year<<(((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) == 1 ? "年是闰年" : "年是平年")<<std::endl;
    return 0;
}

C语言:

#include <stdio.h>
int main(void)
{
    int y;
    printf("请输入年份,回车结束\n");
    scanf("%d",&y);
    if((y%4==0&&y%100!=0)||y%400==0)
        printf("%d是闰年\n",y);
    else
        printf("%d是平年\n",y);
    return 0;
}

Bash/Shell:

year=$1
if [ "$(( $year % 4 ))" == "0" ] && [ "$(( $year % 100 ))" != "0" ] || [ "$(( $year % 400 ))" == "0" ]
then
    echo "leap year"
else
    echo "common year"
fi

Erlang语言:

-module(year).
-export([isLeap/1]).
isLeap(Year) ->
    if Year rem 400 == 0 ->
        true;
    Year rem 100 == 0 ->
        false;
    Year rem 4 == 0 ->
        true;
    true ->
        false
    end.

Ecmascript语言:

// 判断指定年份是否为闰年
function isleap(){
var the_year = new Date().getFullYear();
var isleap = the_year % 4 == 0 && the_year % 100 !=0 || the_year % 400 ==0;
return isleap;
}

VB语言:

Public Function isLeapYear(year As Integer) As Boolean
isLeapYear = (year Mod 4 = 0 And year Mod 100 <> 0) Or year Mod 400 = 0
End Function

MATLAB语言:

function lpflag = isleapyear(year)
% 判断是否为闰年
% Input  -year 年份,数值
% Output -lpflag lpflag = 1,闰年;lpflag = 0,平年
lpflag = (~mod(year, 4) && mod(year, 100)) || ~mod(year, 400);
赞(1) 传送门
本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。墨影 » 闰年