仰望星空的天台

0%

计算两随机年份之间的闰年数

缘由

最近刚好学了表单,表单里有个验证日期,怎么优雅的验证日期呢?想了想,还是用正则吧,然后去学正则,学着学着,就发现了一个号称最强正则的表达式:


((^((1[8-9]\d{2})|([2-9]\d{3}))([-\/\._])(10|12|0?[13578])([-\/\._])(3[01]|[12][0-9]|0?[1-9])$)|(^((1[8-9]\d{2})|([2-9]\d{3}))([-\/\._])(11|0?[469])([-\/\._])(30|[12][0-9]|0?[1-9])$)|(^((1[8-9]\d{2})|([2-9]\d{3}))([-\/\._])(0?2)([-\/\._])(2[0-8]|1[0-9]|0?[1-9])$)|(^([2468][048]00)([-\/\._])(0?2)([-\/\._])(29)$)|(^([3579][26]00)([-\/\._])(0?2)([-\/\._])(29)$)|(^([1][89][0][48])([-\/\._])(0?2)([-\/\._])(29)$)|(^([2-9][0-9][0][48])([-\/\._])(0?2)([-\/\._])(29)$)|(^([1][89][2468][048])([-\/\._])(0?2)([-\/\._])(29)$)|(^([2-9][0-9][2468][048])([-\/\._])(0?2)([-\/\._])(29)$)|(^([1][89][13579][26])([-\/\._])(0?2)([-\/\._])(29)$)|(^([2-9][0-9][13579][26])([-\/\._])(0?2)([-\/\._])(29)$))

可以判断 从 0000 到 9999 年的任意日期是否合法

我去,既然号称最强的表达式,当然要学啊,然后就开始看博主娓娓道来。看到一半,发现有个叫闰年判断的算法看不懂(好吧我小学数学是体育老师教的)

然后就去查百度关于闰年的计算

闰年的定义(摘自百度):

地球绕太阳运行周期为365天5小时48分46秒(合365.24219天)即一回归年(tropical year)。公历的平年只有365日,比回归年短约0.2422 日,所余下的时间约为每四年累计一天,故第四年于2月末加1天,使当年的历年长度为366日,这一年就为闰年。现行公历中每400年有97个闰年。按照每四年一个闰年计算,平均每年就要多算出0.0078天,这样经过四百年就会多算出大约3天来。因此每四百年中要减少三个闰年。所以公历规定:年份是整百数时,必须是400的倍数才是闰年;不是400的倍数的年份,即使是4的倍数也不是闰年。

根据上面的定义马上就能想出第一种遍历算法:

function leapYearNum (s , e) {
	var c = 0;
	var a = e;

	do {
		if ( (a%4 === 0 && a%100 !== 0) || (a%400 === 0) ) {
			c++;
		}
		a = --e;
	} while ((e - s) !== 0 );

	if ( (s%4 === 0 && s%100 !== 0) || (s%400 === 0) ) {
		c++;
	}
	
	return c;
}

caveat: 这种方法会将计算的两个年份(若是闰年)包含进去

但是这种算法的性能肯定时不理想的,例如要算出[0,2000] 就要遍历运算2000次

之后又在CSDN上看到了一种比较简单的思路: 通过算计每个年份到元年的闰年数目 然后做差


function leapYearNum ( s , e ) {
	var M = Math;
	var Int = parseInt;

	return c(e) - c(s);

	// count has much year form Year Zero to this year 
	function c ( y ) {
		var a = Int(y / 100);  
		var n = a * 24;        
		var k = Int(y / 400);
		var v = Int((y - a*100) / 4);

		return k + n + v;
	}
}

// 得到两年份之间所有的闰年数 , 不包含边界
console.log(leapYearNum( 0 , 2016 ));    // 489
console.log(leapYearNum( 1999 , 2002 )); // 1 
console.log( leapYearNum( 1996 , 2029 ) ) // 8

效率就快很多了

Table of Contents