前言
如何计算年龄?我的第一直觉做法:(当前时间戳 - 出生时的时间戳)/ (365*86400) 所得结果向下取整。后来发现这种做法获得的结果不准确,不是多了一岁就是少了一岁,不能简单粗暴的这么处理,只能把相差的年数月数天数精确的算出来。我一开始以为这个很简单,这个问题不值得记录下来,后来发现不是这么一回事,实现起来没有那么顺利,对我而言。
闰年
要计算2个日期之间的相差的时间,肯定需要知道闰年是咋回事。地球绕太阳公转一圈的时间即为公历一年的时间,地球公转花的时间大概是365天5小时48分,这样每隔4年差不多公历时间多出了一天,这一年天文学家称之为闰年,闰年的2月份是29天。前人总结出来闰年的判断方法:年份能被400整除或者年份不能被100整除且能被4整除。(备注:我对公农历不是很了解,这些信息也是从网上找到的,我对这些不是很感兴趣,没有花更多的时间深入的了解)
实现
先算出相差的年数,再算相差的月数,最后计算相差的天数,思路很简单,真正的实现不是一帆风顺。
代码
/** * @desc 计算年龄 * 计算年份->计算月份->计算天数 * * @date 2015-09-22 * @author WadeYu */ var getDiffYmdBetweenDate = function(sDate1,sDate2){ var fixDate = function(sDate){ var aD = sDate.split('-'); for(var i = 0; i < aD.length; i++){ aD[i] = fixZero(parseInt(aD[i])); } return aD.join('-'); }; var fixZero = function(n){ return n < 10 ? '0'+n : n; }; var fixInt = function(a){ for(var i = 0; i < a.length; i++){ a[i] = parseInt(a[i]); } return a; }; var getMonthDays = function(y,m){ var aMonthDays = [0,31,28,31,30,31,30,31,31,30,31,30,31]; if((y%400 == 0) || (y%4==0 && y%100!=0)){ aMonthDays[2] = 29; } return aMonthDays[m]; }; var checkDate = function(sDate){ }; var y = 0; var m = 0; var d = 0; var sTmp; var aTmp; sDate1 = fixDate(sDate1); sDate2 = fixDate(sDate2); if(sDate1 > sDate2){ sTmp = sDate2; sDate2 = sDate1; sDate1 = sTmp; } var aDate1 = sDate1.split('-'); aDate1 = fixInt(aDate1); var aDate2 = sDate2.split('-'); aDate2 = fixInt(aDate2); //计算相差的年份 /*aTmp = [aDate1[0]+1,fixZero(aDate1[1]),fixZero(aDate1[2])]; while(aTmp.join('-') <= sDate2){ y++; aTmp[0]++; }*/ y = aDate2[0] - aDate1[0]; if( sDate2.replace(aDate2[0],'') < sDate1.replace(aDate1[0],'')){ y = y - 1; } //计算月份 aTmp = [aDate1[0]+y,aDate1[1],fixZero(aDate1[2])]; while(true){ if(aTmp[1] == 12){ aTmp[0]++; aTmp[1] = 1; }else{ aTmp[1]++; } if(([aTmp[0],fixZero(aTmp[1]),aTmp[2]]).join('-') <= sDate2){ m++; } else { break; } } //计算天数 aTmp = [aDate1[0]+y,aDate1[1]+m,aDate1[2]]; if(aTmp[1] > 12){ aTmp[0]++; aTmp[1] -= 12; } while(true){ if(aTmp[2] == getMonthDays(aTmp[0],aTmp[1])){ aTmp[1]++; aTmp[2] = 1; } else { aTmp[2]++; } sTmp = ([aTmp[0],fixZero(aTmp[1]),fixZero(aTmp[2])]).join('-'); if(sTmp <= sDate2){ d++; } else { break; } } return {y:y,m:m,d:d}; }; var aTest = [ ['1984-9-17','2015-8-15'], ['1984-9-17','1985-9-18'], ['1984-9-17','1984-10-17'], ['1984-9-17','1984-10-10'], ]; for(var i = 0; i < aTest.length; i++){ console.log(aTest[i][0]+':'+aTest[i][1]); console.log(getDiffYmdBetweenDate(aTest[i][0],aTest[i][1])); }
后记
1.这个问题的实现花了一些时间思考,一开始不是很想记录下,后来想想毕竟是花了时间思考,现在健忘比较严重,还是记录下吧。
2.跟同事讨论,年龄计算是否需要包含当天生日那天,讨论的结果是不包含,没过生日这天年龄不增加,也算刷新了一个基本常识吧。
3.能算出相差的年数月数天数,如果只需要计算总天数或者总月数就很简单了。
4.农历年份会变化,不能根据农历日期来算年龄
5.PHP农历公历转换类,感谢此类的作者
<?php /** * 阴历,阳历,日历转换 */ class o_calendar { public static $MIN_YEAR = 1600; public static $MAX_YEAR = 2200; //public static $lunarInfo = array(array(0,2,9,21936),array(6,1,30,9656),array(0,2,17,9584),array(0,2,6,21168),array(5,1,26,43344),array(0,2,13,59728),array(0,2,2,27296),array(3,1,22,44368),array(0,2,10,43856),array(8,1,31,19304),array(0,2,19,19168),array(0,2,8,42352),array(5,1,29,21096),array(0,2,16,53856),array(0,2,4,55632),array(4,1,25,27304),array(0,2,13,22176),array(0,2,2,39632),array(2,1,22,19176),array(0,2,10,19168),array(6,1,30,42200),array(0,2,18,42192),array(0,2,6,53840),array(5,1,26,54568),array(0,2,14,46400),array(0,2,3,54944),array(2,1,23,38608),array(0,2,11,38320),array(7,2,1,18872),array(0,2,20,18800),array(0,2,8,42160),array(5,1,28,45656),array(0,2,16,27216),array(0,2,5,27968),array(4,1,24,44456),array(0,2,13,11104),array(0,2,2,38256),array(2,1,23,18808),array(0,2,10,18800),array(6,1,30,25776),array(0,2,17,54432),array(0,2,6,59984),array(5,1,26,27976),array(0,2,14,23248),array(0,2,4,11104),array(3,1,24,37744),array(0,2,11,37600),array(7,1,31,51560),array(0,2,19,51536),array(0,2,8,54432),array(6,1,27,55888),array(0,2,15,46416),array(0,2,5,22176),array(4,1,25,43736),array(0,2,13,9680),array(0,2,2,37584),array(2,1,22,51544),array(0,2,10,43344),array(7,1,29,46248),array(0,2,17,27808),array(0,2,6,46416),array(5,1,27,21928),array(0,2,14,19872),array(0,2,3,42416),array(3,1,24,21176),array(0,2,12,21168),array(8,1,31,43344),array(0,2,18,59728),array(0,2,8,27296),array(6,1,28,44368),array(0,2,15,43856),array(0,2,5,19296),array(4,1,25,42352),array(0,2,13,42352),array(0,2,2,21088),array(3,1,21,59696),array(0,2,9,55632),array(7,1,30,23208),array(0,2,17,22176),array(0,2,6,38608),array(5,1,27,19176),array(0,2,15,19152),array(0,2,3,42192),array(4,1,23,53864),array(0,2,11,53840),array(8,1,31,54568),array(0,2,18,46400),array(0,2,7,46752),array(6,1,28,38608),array(0,2,16,38320),array(0,2,5,18864),array(4,1,25,42168),array(0,2,13,42160),array(10,2,2,45656),array(0,2,20,27216),array(0,2,9,27968),array(6,1,29,44448),array(0,2,17,43872),array(0,2,6,38256),array(5,1,27,18808),array(0,2,15,18800),array(0,2,4,25776),array(3,1,23,27216),array(0,2,10,59984),array(8,1,31,27432),array(0,2,19,23232),array(0,2,7,43872),array(5,1,28,37736),array(0,2,16,37600),array(0,2,5,51552),array(4,1,24,54440),array(0,2,12,54432),array(0,2,1,55888),array(2,1,22,23208),array(0,2,9,22176),array(7,1,29,43736),array(0,2,18,9680),array(0,2,7,37584),array(5,1,26,51544),array(0,2,14,43344),array(0,2,3,46240),array(4,1,23,46416),array(0,2,10,44368),array(9,1,31,21928),array(0,2,19,19360),array(0,2,8,42416),array(6,1,28,21176),array(0,2,16,21168),array(0,2,5,43312),array(4,1,25,29864),array(0,2,12,27296),array(0,2,1,44368),array(2,1,22,19880),array(0,2,10,19296),array(6,1,29,42352),array(0,2,17,42208),array(0,2,6,53856),array(5,1,26,59696),array(0,2,13,54576),array(0,2,3,23200),array(3,1,23,27472),array(0,2,11,38608),array(11,1,31,19176),array(0,2,19,19152),array(0,2,8,42192),array(6,1,28,53848),array(0,2,15,53840),array(0,2,4,54560),array(5,1,24,55968),array(0,2,12,46496),array(0,2,1,22224),array(2,1,22,19160),array(0,2,10,18864),array(7,1,30,42168),array(0,2,17,42160),array(0,2,6,43600),array(5,1,26,46376),array(0,2,14,27936),array(0,2,2,44448),array(3,1,23,21936),array(0,2,11,37744),array(8,2,1,18808),array(0,2,19,18800),array(0,2,8,25776),array(6,1,28,27216),array(0,2,15,59984),array(0,2,4,27424),array(4,1,24,43872),array(0,2,12,43744),array(0,2,2,37600),array(3,1,21,51568),array(0,2,9,51552),array(7,1,29,54440),array(0,2,17,54432),array(0,2,5,55888),array(5,1,26,23208),array(0,2,14,22176),array(0,2,3,42704),array(4,1,23,21224),array(0,2,11,21200),array(8,1,31,43352),array(0,2,19,43344),array(0,2,7,46240),array(6,1,27,46416),array(0,2,15,44368),array(0,2,5,21920),array(4,1,24,42448),array(0,2,12,42416),array(0,2,2,21168),array(3,1,22,43320),array(0,2,9,26928),array(7,1,29,29336),array(0,2,17,27296),array(0,2,6,44368),array(5,1,26,19880),array(0,2,14,19296),array(0,2,3,42352),array(4,1,24,21104),array(0,2,10,53856),array(8,1,30,59696),array(0,2,18,54560),array(0,2,7,55968),array(6,1,27,27472),array(0,2,15,22224),array(0,2,5,19168),array(4,1,25,42216),array(0,2,12,42192),array(0,2,1,53584),array(2,1,21,55592),array(0,2,9,54560)); public static $lunarInfo = array(array(0,2,15,9680),array(0,2,3,37584),array(3,1,23,51544),array(0,2,11,43344),array(7,1,31,46248),array(0,2,18,27296),array(0,2,7,44368),array(6,1,28,21928),array(0,2,16,19360),array(0,2,4,42416),array(4,1,25,21176),array(0,2,13,21168),array(0,2,2,26928),array(2,1,21,29864),array(0,2,9,27296),array(6,1,29,44368),array(0,2,17,39760),array(0,2,6,19296),array(4,1,26,42352),array(0,2,14,42224),array(0,2,4,21088),array(3,1,22,59696),array(0,2,10,54576),array(8,1,31,23208),array(0,2,19,22176),array(0,2,7,38608),array(5,1,28,19176),array(0,2,16,19152),array(0,2,5,42192),array(4,1,24,53864),array(0,2,12,45648),array(0,2,1,54560),array(2,1,21,55968),array(0,2,8,46496),array(6,1,29,38352),array(0,2,17,38320),array(0,2,7,18864),array(5,1,26,42168),array(0,2,14,42160),array(0,2,3,43600),array(3,1,23,46376),array(0,2,10,27968),array(0,1,30,44448),array(0,2,18,43872),array(0,2,8,37744),array(5,1,28,18808),array(0,2,16,18800),array(0,2,5,25776),array(4,1,25,27216),array(0,2,11,55888),array(0,2,1,27424),array(1,1,21,43872),array(0,2,9,43744),array(6,1,29,37608),array(0,2,17,37600),array(0,2,6,51552),array(5,1,26,54440),array(0,2,13,54432),array(0,2,2,55888),array(3,1,23,23208),array(0,2,11,22176),array(8,1,30,42704),array(0,2,18,42448),array(0,2,8,37584),array(6,1,28,43352),array(0,2,15,43344),array(0,2,4,46240),array(4,1,24,46416),array(0,2,12,44368),array(0,2,1,21920),array(2,1,21,42448),array(0,2,9,42416),array(7,1,30,21176),array(0,2,17,21104),array(0,2,6,26928),array(5,1,26,29864),array(0,2,14,27296),array(0,2,2,44368),array(3,1,23,19880),array(0,2,11,19296),array(8,1,31,42352),array(0,2,18,42208),array(0,2,7,53856),array(6,1,27,59696),array(0,2,15,54560),array(0,2,3,55968),array(4,1,24,23376),array(0,2,12,22224),array(0,2,2,19168),array(3,1,21,42216),array(0,2,9,42192),array(7,1,29,53848),array(0,2,17,43600),array(0,2,5,46368),array(5,1,25,54944),array(0,2,13,46496),array(0,2,3,21968),array(3,1,23,19160),array(0,2,11,18864),array(7,1,31,42168),array(0,2,19,42160),array(0,2,8,43600),array(6,1,28,46376),array(0,2,16,27936),array(0,2,5,44384),array(4,1,25,21936),array(0,2,13,37744),array(0,2,3,18800),array(3,1,23,42168),array(0,2,10,25776),array(7,1,30,27216),array(0,2,17,55888),array(0,2,7,23200),array(5,1,26,43856),array(0,2,14,43744),array(0,2,4,21216),array(3,1,24,51568),array(0,2,11,51552),array(8,1,31,54440),array(0,2,19,54432),array(0,2,8,54608),array(6,1,28,23208),array(0,2,16,22176),array(0,2,5,42704),array(4,1,26,21224),array(0,2,13,21200),array(0,2,2,43344),array(2,1,22,54440),array(0,2,10,45728),array(7,1,29,46416),array(0,2,17,44368),array(0,2,7,19872),array(5,1,27,42448),array(0,2,14,42416),array(0,2,4,21168),array(4,1,24,43192),array(0,2,12,26928),array(9,1,31,27288),array(0,2,19,27296),array(0,2,8,43856),array(6,1,29,19880),array(0,2,16,19296),array(0,2,5,42352),array(4,1,26,20848),array(0,2,13,53600),array(0,2,1,59696),array(3,1,22,27280),array(0,2,9,55968),array(7,1,30,23376),array(0,2,17,22224),array(0,2,7,19168),array(5,1,27,42216),array(0,2,15,41680),array(0,2,3,53584),array(4,1,23,54440),array(0,2,11,46368),array(9,1,31,54928),array(0,2,18,44448),array(0,2,8,21968),array(6,1,29,10968),array(0,2,17,17840),array(0,2,5,41648),array(5,1,25,45400),array(0,2,13,43344),array(0,2,2,46368),array(2,1,21,46480),array(0,2,9,44384),array(7,1,30,21936),array(0,2,18,21360),array(0,2,7,17776),array(5,1,27,25272),array(0,2,15,21168),array(0,2,4,26960),array(3,1,23,27816),array(0,2,11,23200),array(10,1,31,43856),array(0,2,19,42704),array(0,2,8,19168),array(6,1,28,42352),array(0,2,16,42336),array(0,2,5,53920),array(5,1,24,59728),array(0,2,12,54608),array(0,2,2,23200),array(3,1,22,43856),array(0,2,9,42704),array(7,1,30,19176),array(0,2,18,19120),array(0,2,7,43216),array(5,1,26,53864),array(0,2,14,45728),array(0,2,3,46416),array(4,1,24,22184),array(0,2,11,19872),array(0,1,31,38320),array(2,1,21,19128),array(0,2,9,18864),array(6,1,28,43192),array(0,2,16,25776),array(0,2,5,27280),array(4,1,25,46416),array(0,2,13,27472),array(0,2,3,11168),array(2,1,23,38320),array(0,2,11,37744),array(7,1,31,20848),array(0,2,18,53600),array(0,2,7,58544),array(5,1,28,27280),array(0,2,14,55952),array(0,2,4,23376),array(3,1,25,11112),array(0,2,13,10976),array(0,2,1,37600),array(2,1,21,53608),array(0,2,9,51536),array(6,1,29,54440),array(0,2,16,46240),array(0,2,5,46736),array(4,1,26,22224),array(0,2,14,21936),array(0,2,3,9680),array(3,1,23,41688),array(0,2,11,37552),array(7,1,31,43352),array(0,2,18,43344),array(0,2,7,46240),array(5,1,27,46416),array(0,2,15,44368),array(0,2,4,21936),array(4,1,25,9656),array(0,2,13,9584),array(9,2,2,21176),array(0,2,20,21168),array(0,2,9,26960),array(6,1,29,27816),array(0,2,17,23200),array(0,2,5,43856),array(4,1,26,21352),array(0,2,14,19168),array(0,2,3,42352),array(3,1,23,21168),array(0,2,10,53856),array(7,1,30,59728),array(0,2,18,54608),array(0,2,7,23200),array(5,1,27,43728),array(0,2,15,38352),array(0,2,5,19168),array(4,1,24,42200),array(0,2,12,42192),array(8,2,1,53848),array(0,2,20,45712),array(0,2,8,46416),array(7,1,29,22184),array(0,2,17,11680),array(0,2,6,38320),array(5,1,26,19128),array(0,2,14,18864),array(0,2,3,42160),array(3,1,23,45656),array(0,2,10,27216),array(8,1,30,44360),array(0,2,18,27472),array(0,2,8,11104),array(5,1,27,38320),array(0,2,15,37744),array(0,2,5,18800),array(4,1,25,25776),array(0,2,11,54432),array(10,1,31,59984),array(0,2,19,55952),array(0,2,9,23248),array(6,1,29,11112),array(0,2,17,10976),array(0,2,6,37600),array(5,1,26,51560),array(0,2,13,51536),array(0,2,2,54432),array(3,1,22,55888),array(0,2,10,46672),array(7,1,30,22224),array(0,2,18,21936),array(0,2,8,9680),array(5,1,28,37592),array(0,2,15,37552),array(0,2,4,43344),array(4,1,24,46248),array(0,2,12,46240),array(0,1,31,46416),array(2,1,21,22184),array(0,2,9,21936),array(6,1,30,9656),array(0,2,17,9584),array(0,2,6,21168),array(5,1,26,43344),array(0,2,13,59728),array(0,2,2,27296),array(3,1,22,44368),array(0,2,10,43856),array(8,1,31,19304),array(0,2,19,19168),array(0,2,8,42352),array(5,1,29,21096),array(0,2,16,53856),array(0,2,4,55632),array(4,1,25,27304),array(0,2,13,22176),array(0,2,2,39632),array(2,1,22,19176),array(0,2,10,19168),array(6,1,30,42200),array(0,2,18,42192),array(0,2,6,53840),array(5,1,26,54568),array(0,2,14,46400),array(0,2,3,54944),array(2,1,23,38608),array(0,2,11,38320),array(7,2,1,18872),array(0,2,20,18800),array(0,2,8,42160),array(5,1,28,45656),array(0,2,16,27216),array(0,2,5,27968),array(4,1,24,44456),array(0,2,13,11104),array(0,2,2,38256),array(2,1,23,18808),array(0,2,10,18800),array(6,1,30,25776),array(0,2,17,54432),array(0,2,6,59984),array(5,1,26,27976),array(0,2,14,23248),array(0,2,4,11104),array(3,1,24,37744),array(0,2,11,37600),array(7,1,31,51560),array(0,2,19,51536),array(0,2,8,54432),array(6,1,27,55888),array(0,2,15,46416),array(0,2,5,22176),array(4,1,25,43736),array(0,2,13,9680),array(0,2,2,37584),array(2,1,22,51544),array(0,2,10,43344),array(7,1,29,46248),array(0,2,17,27808),array(0,2,6,46416),array(5,1,27,21928),array(0,2,14,19872),array(0,2,3,42416),array(3,1,24,21176),array(0,2,12,21168),array(8,1,31,43344),array(0,2,18,59728),array(0,2,8,27296),array(6,1,28,44368),array(0,2,15,43856),array(0,2,5,19296),array(4,1,25,42352),array(0,2,13,42352),array(0,2,2,21088),array(3,1,21,59696),array(0,2,9,55632),array(7,1,30,23208),array(0,2,17,22176),array(0,2,6,38608),array(5,1,27,19176),array(0,2,15,19152),array(0,2,3,42192),array(4,1,23,53864),array(0,2,11,53840),array(8,1,31,54568),array(0,2,18,46400),array(0,2,7,46752),array(6,1,28,38608),array(0,2,16,38320),array(0,2,5,18864),array(4,1,25,42168),array(0,2,13,42160),array(10,2,2,45656),array(0,2,20,27216),array(0,2,9,27968),array(6,1,29,44448),array(0,2,17,43872),array(0,2,6,38256),array(5,1,27,18808),array(0,2,15,18800),array(0,2,4,25776),array(3,1,23,27216),array(0,2,10,59984),array(8,1,31,27432),array(0,2,19,23232),array(0,2,7,43872),array(5,1,28,37736),array(0,2,16,37600),array(0,2,5,51552),array(4,1,24,54440),array(0,2,12,54432),array(0,2,1,55888),array(2,1,22,23208),array(0,2,9,22176),array(7,1,29,43736),array(0,2,18,9680),array(0,2,7,37584),array(5,1,26,51544),array(0,2,14,43344),array(0,2,3,46240),array(4,1,23,46416),array(0,2,10,44368),array(9,1,31,21928),array(0,2,19,19360),array(0,2,8,42416),array(6,1,28,21176),array(0,2,16,21168),array(0,2,5,43312),array(4,1,25,29864),array(0,2,12,27296),array(0,2,1,44368),array(2,1,22,19880),array(0,2,10,19296),array(6,1,29,42352),array(0,2,17,42208),array(0,2,6,53856),array(5,1,26,59696),array(0,2,13,54576),array(0,2,3,23200),array(3,1,23,27472),array(0,2,11,38608),array(11,1,31,19176),array(0,2,19,19152),array(0,2,8,42192),array(6,1,28,53848),array(0,2,15,53840),array(0,2,4,54560),array(5,1,24,55968),array(0,2,12,46496),array(0,2,1,22224),array(2,1,22,19160),array(0,2,10,18864),array(7,1,30,42168),array(0,2,17,42160),array(0,2,6,43600),array(5,1,26,46376),array(0,2,14,27936),array(0,2,2,44448),array(3,1,23,21936),array(0,2,11,37744),array(8,2,1,18808),array(0,2,19,18800),array(0,2,8,25776),array(6,1,28,27216),array(0,2,15,59984),array(0,2,4,27424),array(4,1,24,43872),array(0,2,12,43744),array(0,2,2,37600),array(3,1,21,51568),array(0,2,9,51552),array(7,1,29,54440),array(0,2,17,54432),array(0,2,5,55888),array(5,1,26,23208),array(0,2,14,22176),array(0,2,3,42704),array(4,1,23,21224),array(0,2,11,21200),array(8,1,31,43352),array(0,2,19,43344),array(0,2,7,46240),array(6,1,27,46416),array(0,2,15,44368),array(0,2,5,21920),array(4,1,24,42448),array(0,2,12,42416),array(0,2,2,21168),array(3,1,22,43320),array(0,2,9,26928),array(7,1,29,29336),array(0,2,17,27296),array(0,2,6,44368),array(5,1,26,19880),array(0,2,14,19296),array(0,2,3,42352),array(4,1,24,21104),array(0,2,10,53856),array(8,1,30,59696),array(0,2,18,54560),array(0,2,7,55968),array(6,1,27,27472),array(0,2,15,22224),array(0,2,5,19168),array(4,1,25,42216),array(0,2,12,42192),array(0,2,1,53584),array(2,1,21,55592),array(0,2,9,54560),array(7,1,29,55952),array(0,2,17,46496),array(0,2,7,21968),array(5,1,28,19160),array(0,2,15,18864),array(0,2,4,42160),array(4,1,24,53848),array(0,2,12,43600),array(9,1,31,46376),array(0,2,19,27936),array(0,2,8,44384),array(6,1,29,21936),array(0,2,16,37744),array(0,2,6,18800),array(4,1,26,25784),array(0,2,14,21680),array(0,2,2,27216),array(3,1,22,27944),array(0,2,10,27296),array(7,1,30,43856),array(0,2,17,43728),array(0,2,7,21216),array(5,1,27,51568),array(0,2,15,43360),array(0,2,3,54432),array(4,1,23,59984),array(0,2,11,55632),array(0,2,1,23200),array(0,2,19,22176),array(0,2,8,42704),array(6,1,29,21224),array(0,2,17,21200),array(0,2,5,43216),array(5,1,25,54440),array(0,2,13,45728),array(0,2,2,46416),array(2,1,22,22184),array(0,2,10,21920),array(7,1,30,42448),array(0,2,18,42416),array(0,2,7,21168),array(5,1,27,43192),array(0,2,15,26800),array(0,2,4,29328),array(4,1,23,46416),array(0,2,11,27472),array(0,2,1,11680),array(0,2,20,19296),array(0,2,8,42352),array(6,1,29,20848),array(0,2,16,53600),array(0,2,5,59568),array(5,1,25,27280),array(0,2,12,55952),array(0,2,2,23376),array(3,1,23,11112),array(0,2,10,10976),array(7,1,30,41704),array(0,2,18,41680),array(0,2,7,53584),array(6,1,26,54440),array(0,2,14,46368),array(0,2,3,54928),array(4,1,24,23248),array(0,2,11,21936),array(10,2,1,10968),array(0,2,20,17840),array(0,2,9,41648),array(6,1,28,43352),array(0,2,16,43344),array(0,2,5,46240),array(5,1,25,46416),array(0,2,12,44368),array(0,2,2,21936),array(3,1,23,9656),array(0,2,11,17776),array(7,1,30,25272),array(0,2,18,21168),array(0,2,7,26960),array(6,1,27,27816),array(0,2,14,23200),array(0,2,3,43856),array(4,1,24,21352),array(0,2,12,19168),array(0,1,31,42352),array(2,1,21,21168),array(0,2,8,53920),array(6,1,28,59728),array(0,2,15,54608),array(0,2,5,23200),array(5,1,25,43856),array(0,2,13,42704),array(0,2,2,19168),array(3,1,22,42328),array(0,2,10,42192),array(7,1,30,53848),array(0,2,17,45712),array(0,2,6,46416),array(6,1,27,22184),array(0,2,15,11680)); /** * 将阳历转换为阴历 * @param year 公历-年 * @param month 公历-月 * @param date 公历-日 */ public static function convertSolarToLunar($year,$month,$date){ $yearData = self::$lunarInfo[$year-self::$MIN_YEAR]; if($year==self::$MIN_YEAR&&$month<=2&&$date<=9){ return array('1891-01-01',false); } $ret = self::getLunarByBetween($year,self::getDaysBetweenSolar($year,$month,$date,$yearData[1],$yearData[2])); $ret[0] = fn::formatDate($ret[0]); return $ret; } /** * 将阴历转换为阳历 * @param year 阴历-年 * @param month 阴历-月,闰月处理:例如如果当年闰五月,那么第二个五月就传六月,相当于阴历有13个月,只是有的时候第13个月的天数为0 * @param date 阴历-日 */ public static function convertLunarToSolar($year,$month,$date){ $yearData = self::$lunarInfo[$year-self::$MIN_YEAR]; $between = self::getDaysBetweenLunar($year,$month,$date); $res = mktime(0,0,0,$yearData[1],$yearData[2],$year); return date('Y-m-d',$res+$between*24*60*60); } /** * 判断是否是闰年 * @param year */ public static function isLeapYear($year){ return (($year%4==0 && $year%100 !=0) || ($year%400==0)); } /** * 获取干支纪年 * @param year */ public static function getLunarYearName($year){ $sky = array('庚','辛','壬','癸','甲','乙','丙','丁','戊','己'); $earth = array('申','酉','戌','亥','子','丑','寅','卯','辰','巳','午','未'); $year = $year.''; return $sky[$year{3}].$earth[$year%12]; } /** * 根据阴历年获取生肖 * @param year 阴历年 */ public static function getYearZodiac($year){ $zodiac = array('猴','鸡','狗','猪','鼠','牛','虎','兔','龙','蛇','马','羊'); return $zodiac[$year%12]; } /** * 获取阳历月份的天数 * @param year 阳历-年 * @param month 阳历-月 */ public static function getSolarMonthDays($year,$month){ $monthHash = array('1'=>31,'2'=>self::isLeapYear($year)?29:28,'3'=>31,'4'=>30,'5'=>31,'6'=>30,'7'=>31,'8'=>31,'9'=>30,'10'=>31,'11'=>30,'12'=>31); return $monthHash["$month"]; } /** * 获取阴历月份的天数 * @param year 阴历-年 * @param month 阴历-月,从一月开始 */ public static function getLunarMonthDays($year,$month){ $monthData = self::getLunarMonths($year); return $monthData[$month-1]; } /** * 获取阴历每月的天数的数组 * @param year */ public static function getLunarMonths($year){ $yearData = self::$lunarInfo[$year - self::$MIN_YEAR]; $leapMonth = $yearData[0]; $bit = decbin($yearData[3]); for ($i = 0; $i < strlen($bit);$i ++) { $bitArray[$i] = substr($bit, $i, 1); } for($k=0,$klen=16-count($bitArray);$k<$klen;$k++){ array_unshift($bitArray, '0'); } $bitArray = array_slice($bitArray,0,($leapMonth==0?12:13)); for($i=0; $i<count($bitArray); $i++){ $bitArray[$i] = $bitArray[$i] + 29; } return $bitArray; } /** * 获取农历每年的天数 * @param year 农历年份 */ public static function getLunarYearDays($year){ $yearData = self::$lunarInfo[$year-self::$MIN_YEAR]; $monthArray = self::getLunarYearMonths($year); $len = count($monthArray); return ($monthArray[$len-1]==0?$monthArray[$len-2]:$monthArray[$len-1]); } public static function getLunarYearMonths($year){ //debugger; $monthData = self::getLunarMonths($year); $res=array(); $temp=0; $yearData = self::$lunarInfo[$year-self::$MIN_YEAR]; $len = ($yearData[0]==0?12:13); for($i=0;$i<$len;$i++){ $temp=0; for($j=0;$j<=$i;$j++){ $temp+=$monthData[$j]; } array_push($res, $temp); } return $res; } /** * 获取闰月 * @param year 阴历年份 */ public static function getLeapMonth($year){ $yearData = self::$lunarInfo[$year-self::$MIN_YEAR]; return $yearData[0]; } /** * 计算阴历日期与正月初一相隔的天数 * @param year * @param month * @param date */ public static function getDaysBetweenLunar($year,$month,$date){ $yearMonth = self::getLunarMonths($year); $res=0; for($i=1;$i<$month;$i++){ $res +=$yearMonth[$i-1]; } $res+=$date-1; return $res; } /** * 计算2个阳历日期之间的天数 * @param year 阳历年 * @param cmonth * @param cdate * @param dmonth 阴历正月对应的阳历月份 * @param ddate 阴历初一对应的阳历天数 */ public static function getDaysBetweenSolar($year,$cmonth,$cdate,$dmonth,$ddate){ $a = mktime(0,0,0,$cmonth,$cdate,$year); $b = mktime(0,0,0,$dmonth,$ddate,$year); return ceil(($a-$b)/24/3600); } /** * 根据距离正月初一的天数计算阴历日期 * @param year 阳历年 * @param between 天数 */ public static function getLunarByBetween($year,$between){ //debugger; $lunarArray = array(); $yearMonth=array(); $t=0; $e=0; $leapMonth=0; $m=''; $isLeap = false; if($between==0){ array_push($lunarArray, $year,'正月','初一'); $t = 1; $e = 1; $month = $t; }else{ $year = $between>0? $year : ($year-1); $yearMonth = self::getLunarYearMonths($year); $leapMonth = self::getLeapMonth($year); $between = $between>0?$between : (self::getLunarYearDays($year)+$between); for($i=0;$i<13;$i++){ if($between==$yearMonth[$i]){ $t=$i+2; $e=1; break; }else if($between<$yearMonth[$i]){ $t=$i+1; $e=$between-(empty($yearMonth[$i-1])?0:$yearMonth[$i-1])+1; break; } } if ($leapMonth!=0&&$t==$leapMonth+1) { $month = $t- 1; $isLeap = true; }else{ $month = $leapMonth!=0&&$leapMonth+1<$t?($t-1):$t; $isLeap; } //$m = ($leapMonth!=0&&$t==$leapMonth+1)?('闰'.self::getCapitalNum($t- 1,true)):self::getCapitalNum(($leapMonth!=0&&$leapMonth+1<$t?($t-1):$t),true); //array_push($lunarArray,$year,$m,self::getCapitalNum($e,false)); } return array($year . '-' . $month . '-' . $e, $isLeap); //array_push($lunarArray,self::getLunarYearName($year));//天干地支 //array_push($lunarArray,$t,$e); //array_push($lunarArray,self::getYearZodiac($year));//12生肖 //array_push($lunarArray,$leapMonth);//闰几月 //return $lunarArray; } /** * 获取数字的阴历叫法 * @param num 数字 * @param isMonth 是否是月份的数字 */ public static function getCapitalNum($num,$isMonth){ $isMonth = $isMonth || false; $dateHash=array('0'=>'','1'=>'一','2'=>'二','3'=>'三','4'=>'四','5'=>'五','6'=>'六','7'=>'七','8'=>'八','9'=>'九','10'=>'十'); $monthHash=array('0'=>'','1'=>'正月','2'=>'二月','3'=>'三月','4'=>'四月','5'=>'五月','6'=>'六月','7'=>'七月','8'=>'八月','9'=>'九月','10'=>'十月','11'=>'冬月','12'=>'腊月'); $res=''; if($isMonth){ $res = $monthHash[$num]; }else{ if($num<=10){ $res = '初'.$dateHash[$num]; }else if($num>10&&$num<20){ $res = '十'.$dateHash[$num-10]; }else if($num==20){ $res = "二十"; }else if($num>20&&$num<30){ $res = "廿".$dateHash[$num-20]; }else if($num==30){ $res = "三十"; } } return $res; } /** * * @param unknown $y * @param unknown $m * @param unknown $d * @param unknown $time */ public static function getSolarAndLunarTime($y, $m, $d , $time){ $aTime = explode(':', $time); $sSolar = $y . cfg::lang('year') . $m . cfg::lang('month') . $d . cfg::lang('day') . ' ' . $aTime[0] . cfg::lang('hour') . $aTime[1] . cfg::lang('minute'); $aLunarRes = calendarswach::convertSolarToLunar($y, $m, $d); $lunarDate = $aLunarRes[0];//阴历日期 $isLeap = $aLunarRes[1];//是否闰月 $aLunar = explode('-', $lunarDate); $blockNumber = cfg::lang('blockNumber'); $lunarY = $blockNumber[intval($aLunar[0]{0})] . $blockNumber[intval($aLunar[0]{1})] . $blockNumber[intval($aLunar[0]{2})] . $blockNumber[intval($aLunar[0]{3})]; $calendarLang = cfg::lang('calendar'); $lunarM = $calendarLang['month'][intval($aLunar[1])]; if ($isLeap) { $lunarM = cfg::lang('leap') . $lunarM; } $lunarD = $calendarLang['date'][intval($aLunar[2])]; $aTime = explode(':', $time); $tempHour = ($aTime[0] % 2) == 0 ? $aTime[0] + 2 : $aTime[0] + 3; //奇数+3 偶数 +2 $tempHour = $tempHour % 24; $hourDiZhi = $tempHour / 2; //每两小时一个时辰 if ($hourDiZhi == 0) { $hourDiZhi = 12; } $lang = cfg::lang('diZhi'); $lunarH = $lang[$hourDiZhi] . cfg::lang('lunarhour'); return array('solar' => $sSolar, 'lunar' => $lunarY . cfg::lang('year') . $lunarM . $lunarD . cfg::lang('day') . ' ' . $lunarH); } ///新加的 /** * * @param unknown $sdate * @param unknown $edate */ public static function getGapDays($sdate, $edate){ if($sdate > $edate){ return 0; } $aSdate = explode('-', $sdate); $aEdate = explode('-', $edate); $sYear = $aSdate[0]; $sMonth = (int)$aSdate[1]; $sDate = (int)$aSdate[2]; $eYear = $aEdate[0]; $eMonth = (int)$aEdate[1]; $eDate = (int)$aEdate[2]; $allDays = $yearDays = 0; //同一年 if($sYear == $eYear){ if($sMonth == $eMonth){ //同一个月 return $eDate - $sDate; } //不同月 $isLeap = self::isLeapYear($sYear); $loopMonth = $sMonth; while ($loopMonth <= $eMonth){ if($loopMonth == $sMonth){ $monDays = self::getMonthDays($loopMonth, $isLeap); $allDays += ($monDays - $sDate);//加上这个月剩余的天数 }elseif ($loopMonth == $eMonth){ $allDays += $eDate;//加上末月日期数 }else { $monDays = self::getMonthDays($loopMonth, $isLeap); $allDays += $monDays;//加上这个月的天数 } $loopMonth++; } return $allDays; } //跨年 $aLeapAndGeneral = self::getLongYearsLeapAndGeneral($sYear, $eYear); $yearDays = $aLeapAndGeneral['leapYears'] * 366 + $aLeapAndGeneral['generalYears'] * 365; //var_dump($aLeapAndGeneral,$yearDays, $sYear, $eYear, $allDays); //计算首尾 $loopMonth = $sMonth; $loopYear = $sYear; $isLeap = self::isLeapYear($loopYear); while (1){ if(($loopMonth == $sMonth) && ($loopYear == $sYear) ){ $monDays = self::getMonthDays($loopMonth, $isLeap); $allDays += ($monDays - $sDate);//加上这个月剩余的天数 }elseif (($loopMonth == $eMonth) && ($loopYear == $eYear) ){ $allDays += $eDate;//加上末月日期数 break; }else { $monDays = self::getMonthDays($loopMonth, $isLeap); $allDays += $monDays;//加上这个月的天数 } $loopMonth++; if($loopMonth == 13){ //转到尾年 $loopMonth = 1;//从1月份开始计算 $loopYear = $eYear; $isLeap = self::isLeapYear($loopYear); } } //var_dump($yearDays, $allDays); $allDays += $yearDays; return $allDays; } //计算差距2年(含2年)以上的闰年和平年年 //不含边界 public static function getLongYearsLeapAndGeneral($sYear, $eYear){ $sYear = (int)$sYear; $eYear = (int)$eYear; $gapYears = $eYear - $sYear; if($gapYears < 2){ return array('leapYears' => 0, 'generalYears' => 0); } $leapYears = $generalYears = 0; $firstLeapYear = ++$sYear; $endLeapYear = --$eYear; //5年以内 if($gapYears < 10){ while ($firstLeapYear <= $endLeapYear){ if(self::isLeapYear($firstLeapYear)){ $leapYears++; }else { $generalYears++; } $firstLeapYear++; } return array('leapYears' => $leapYears, 'generalYears' => $generalYears); } //超过5年 //首先找到开始年的下一个闰年 $sEgeneralYears = 0; for ($i = 0; $i < 5; $i++){ if(self::isLeapYear($firstLeapYear)){ break; } $sEgeneralYears++; $firstLeapYear++; } //找到最后一个闰年 for ($i = 0; $i < 5; $i++){ if(self::isLeapYear($endLeapYear)){ break; } $sEgeneralYears++; $endLeapYear--; } //整百的1700 1800 1900 2100 不是瑞年 $noleap100th = self::get100th($firstLeapYear, $endLeapYear); $modGapYears = $endLeapYear - $firstLeapYear; $leapYears = ($modGapYears) / 4; $generalYears = $leapYears * 3; $leapYears = $leapYears + 1 - $noleap100th;//加上边界 减去整100 $generalYears += $noleap100th;//加上整100平年 //加上收尾的平年 $generalYears += $sEgeneralYears; return array('leapYears' => $leapYears, 'generalYears' => $generalYears); } //整百的1700 1800 1900 2100 不是瑞年 public static function get100th($sy, $ey){ $c = 0; foreach (array(1700,1800,1900,2100) as $y){ if ($sy <= $y && $y<= $ey) { $c++; } } return $c; } //获取公历月份天数 public static function getMonthDays($month, $isLeap){ $month = (int)$month; if ($month == 2) { return $isLeap ? 29 : 28; } //1-12月分别为31天,29天,31天,30天,31天,30天,31天,31天,30天,31天,30天,31天 return in_array($month, array(1,3,5,7,8,10,12)) ? 31 : 30; } //获取年干支 public static function getYearGanZhi( $year){ $year = (int)$year; //计算年柱时用的天干/地支排列 $aYearZhuTianGan = array(7,8,9,10,1,2,3,4,5,6); $aYearZhuDizhi = array(9,10,11,12,1,2,3,4,5,6,7,8); $yearTianGan = $aYearZhuTianGan[substr($year, -1)]; $yearDiZhi = $aYearZhuDizhi[$year % 12]; return array('yearTianGan' => $yearTianGan, 'yearDiZhi' => $yearDiZhi); } //获取某一年的所有月干支 /** * * @param unknown $year * @param string $lunar true 阴历 false 阳历 */ public static function getMonthsGanZhiByYear($year, $lunar = false){ $year = (int)$year; //立春在2月,先取二月的干支 $aYearZhuTianGan = array(7,8,9,10,1,2,3,4,5,6); $yearTianGan = $aYearZhuTianGan[substr($year, -1)]; $aYearFirstMonthTiangan = array( 1 => 3, 2 => 5, 3 => 7, 4 => 9, 5 => 1, 6 => 3, 7 => 5, 8 => 7, 9 => 9, 10 => 1); $monthTianGan = $aYearFirstMonthTiangan[$yearTianGan]; $monthDiZhi = 3;//自立春日起固定为寅(从立春当天到惊蛰前一天) $loopTianGan = $monthTianGan; $loopDiZhi = $monthDiZhi; if ($lunar == true) { $leapMonth = self::getLeapMonth($year); $monthCount = $leapMonth > 0 ? 13 : 12; $isLeapSta = 0; for ($i = 1; $i<=$monthCount; $i++){ $month = $i; $isleap = 0; if($isLeapSta == 1){ $month = $i - 1; $isleap = 1; $isLeapSta = 2; }elseif ($isLeapSta == 2){ //闰月后的月份 $month = $i - 1; } $aData[] = array('month' => $month, 'isleap' => $isleap, 'tiangan' => $loopTianGan,'dizhi' => $loopDiZhi); //这里必须放后面 if(($leapMonth == $i) && ($isLeapSta == 0)){ $isLeapSta = 1; } $loopTianGan++; $loopTianGan = $loopTianGan == 11 ? 1 : $loopTianGan; $loopDiZhi++; $loopDiZhi = $loopDiZhi == 13 ? 1 : $loopDiZhi; } }else{ //1月的干支 $oneMonthTianGan = $monthTianGan - 1; $oneMonthTianGan = $oneMonthTianGan == 0 ? 10 : $oneMonthTianGan; $oneMonthDiZhi = 2; $aData = array(); $aData[] = array('month' => 1, 'tiangan' => $oneMonthTianGan, 'dizhi' => $oneMonthDiZhi); $aData[] = array('month' => 2, 'tiangan' => $monthTianGan, 'dizhi' => $monthDiZhi); for ($i=3; $i<=12; $i++){ $loopTianGan++; $loopTianGan = $loopTianGan == 11 ? 1 : $loopTianGan; $loopDiZhi++; $loopDiZhi = $loopDiZhi == 13 ? 1 : $loopDiZhi; $aData[] = array('month' => $i, 'tiangan' => $loopTianGan, 'dizhi' => $loopDiZhi); } } return $aData; } /** * 获取阳历某月的数据 * @param unknown $year * @param unknown $month */ public static function getSolarMonthData($year, $month){ //1600-1-1日 星期六 辛酉日 //阳历月份天数 $days = self::getMonthDays($month, self::isLeapYear($year)); $startDate = '1600-01-01';//辛酉日 $startTianGan = 8; $startDiZhi = 10; $startW = 6;//星期六 $deffDays = calendarswach::getGapDays($startDate, "$year-$month-01") ; $aData = array(); for ($i = 1; $i<= $days; $i++){ $aLunarDate = self::convertSolarToLunar($year, $month, $i); $aLunar = explode('-', $aLunarDate[0]); $week = ($startW + $deffDays) % 7; $dayTianGan = ($startTianGan + $deffDays) % 10; if ($dayTianGan == 0) { $dayTianGan = 10; } $dayDiZhi = ($startDiZhi + $deffDays) % 12; if ($dayDiZhi == 0) { $dayDiZhi = 12; } $aTemp = array(); $aTemp['sd'] = $i;//阳历日期 $aTemp['ly'] = (int)$aLunar[0];//阴历年 $aTemp['lm'] = (int)$aLunar[1];//阴历月 $aTemp['ld'] = (int)$aLunar[2];//阴历日 $aTemp['leap'] = $aLunarDate[1] ? $aTemp['lm'] : 0;//闰几月 $aTemp['w'] = $week;//星期几 $aTemp['tg'] = $dayTianGan;//天干 $aTemp['dz'] = $dayDiZhi;//地支 $aData[] = $aTemp; $deffDays++;//间隔天数+1 } return $aData; } /** * 获取阴历某月的数据 * @param unknown $year * @param unknown $month */ public static function getLunarMonthData($year, $month, $leapMonth){ $month = $leapMonth ? $month +1 : $month; $sdate = self::convertLunarToSolar($year, $month, '1'); $aSolar = explode('-', $sdate); $sy = (int)$aSolar[0]; $sm = (int)$aSolar[1]; $sd = (int)$aSolar[2]; $startDate = '1600-01-01';//辛酉日 $startTianGan = 8; $startDiZhi = 10; $startW = 6;//星期六 $deffDays = calendarswach::getGapDays($startDate, "$sy-$sm-$sd") ;//阳历相隔天数 //阴历大月30天 $monthDays = self::getLunarMonthDays($year, $month); $aData = array(); for ($i=1; $i<=$monthDays; $i++){ $sdate = self::convertLunarToSolar($year, $month, $i); $aSolar = explode('-', $sdate); $week = ($startW + $deffDays) % 7; $dayTianGan = ($startTianGan + $deffDays) % 10; if ($dayTianGan == 0) { $dayTianGan = 10; } $dayDiZhi = ($startDiZhi + $deffDays) % 12; if ($dayDiZhi == 0) { $dayDiZhi = 12; } $aTemp = array(); $aTemp['ld'] = $i;//阴历日期 $aTemp['sy'] = (int)$aSolar[0];//阳历年 $aTemp['sm'] = (int)$aSolar[1];//阳历月 $aTemp['sd'] = (int)$aSolar[2];//阳历日 $aTemp['leap'] = $leapMonth;//闰几月 $aTemp['w'] = $week;//星期几 $aTemp['tg'] = $dayTianGan;//天干 $aTemp['dz'] = $dayDiZhi;//地支 $aData[] = $aTemp; $deffDays++;//间隔天数+1 } return $aData; } //获取日 时干支 public static function getDayHourGanZhis($dayTianGan){ $aDayFirstHourTiangan = array( 1 => 1, 2 => 3, 3 => 5, 4 => 7, 5 => 9, 6 => 1, 7 => 3, 8 => 5, 9 => 7, 10 => 9 ); $aData = array(); for ($hour=0;$hour<=23;$hour++){ $tmpDayTianGan = $dayTianGan;//日天干 $tempHour = ($hour % 2) == 0 ? $hour + 2 : $hour + 3; //奇数+3 偶数 +2 $tempHour = $tempHour % 24; $hourDiZhi = $tempHour / 2; //每两小时一个时辰 if ($hourDiZhi == 0) { $hourDiZhi = 12; } if ($hour > 22) {////时间计算 $tmpDayTianGan = ($tmpDayTianGan + 1) % 10; $tmpDayTianGan = ($tmpDayTianGan == 0 ) ? 10 : $tmpDayTianGan; } $dayFirstTianGan = $aDayFirstHourTiangan[$tmpDayTianGan]; $hourTianGan = ($dayFirstTianGan + ($hourDiZhi - 1)) % 10; $hourTianGan = ($hourTianGan == 0 ) ? 10 : $hourTianGan; $aTemp = array('h' => $hour, 'tg' => $hourTianGan, 'dz' => $hourDiZhi); $aData[] = $aTemp; } return $aData; } } //$ba = gongliNongli::convertLunarToSolar(1924,1,1);
参考资料
[1]如何判断闰月
http://www.cnblogs.com/BpLoveGcy/archive/2010/03/29/1700085.html
[2]闰年知识科普
http://baike.baidu.com/subview/29649/7344239.htm