今天来聊一下闰年这个东西,记得最开始学编程的时候,就有个题是 写个程序判断给定的年份是否是闰年…
闰年是比普通年分多出一段时间的年分,在各种历法中都有出现,目的是为了弥补人为规定的纪年与地球公转产生的差异。
目前使用的格里高利历闰年规则如下:
- 公元年分除以
400
可整除但除以3200
不可整除,为闰年。 - 公元年分除以
4
可整除但除以100
不可整除,为闰年。 - 公元年分除以
4
不可整除,为平年。 - 公元年分除以
100
可整除但除以400
不可整除,为平年。 - 公元年分除以
3200
可整除,为平年。
每逢闰年,2月分有29日,平年的2月分为28日。
计算方法
if ((公元年分是400的倍数)或(公元年分是4的倍数但不是100的倍数))
{
//闰年
} else
{
//平年
}
产生原因
通常的解释是说一年有多少天多少小时多少分,取整数365还有多余的,累积达到一天24小时后,就多加一天的年是闰年。这个解释只是告诉了大家怎么计算,是人为设置的东西。
最根本的原因是:地球绕太阳运行周期为365
天5
小时48
分46
秒(合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”年,等于历法公元前一年。
阳历中的“闰年”
阳历中有闰日的年分叫闰年,相反就是平年,平年为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);