本例设计一个既可以查看公历,又可以查看农历的万年历,并.且在日期的下面显示了公历与农历的各个节日及农历的节气,运行结果如图1所示。
图1 万年历演示效果
本例主要利用Date对象来获取指定日期的相关信息,并用Lunar对象将指定日期转换成相应的农历日期。Date对象是一个有关日期和时间的对象。
【提示】
在JavaScript中,Date对象负责获取和设置时间。在其他语言中,时间是一种数据类型,但是JavaScript仅把时间作为一种特殊格式的字符串来表示,并通过Date对象进行管理。在特殊环境中,时间也可以转换为数值,如时间比较、时间运算。
创建时间对象的方法有4种。
【示例1】获取本地系统的当前时间。
var now = new Date(); alert(now);// 返回当前时间对象,如"Wed Apr 29 15 :37: 55 UTC +0800 2017 "
【示例2】通过多选参数创建指定的时间对象。此时,构造函数Date()的参数格式如下:
new Date(year, month, day, hours, minutes, seconds, ms)
除了前两个参数(年和月)外,其他所有参数都是可选的。其中月数参数从0开始,如0表示第1个月,11表示第12个月。
var d1 = new Date(2017,4,1); alert(d1); // 返回时间对象,如"Fri May 1 00: 00:00 UTC+ 0800 2017" var d2 = new Date(2017,4,1,5,30,30); alert(d2); // 返回时间对象,如"Fri May 1 00: 00:00 UTC+ 0800 2017"
所有声明的日期和时间使用的都是本地时间,而不是UTC时间。
【示例3】通过时间格式字符串创建指定的时间对象。此时,月份是从1开始,而不是从0开始。代码如下:
var d1 = new Date("2017/4/1 5:30:30");
alert(d1); //返回时间对象,如"Wed Apr 1 05 :30: 30 UTC +0800 2017"
【示例4】通过传递一个毫秒数创建指定的时间对象。这个毫秒数是距离1970年1月1日午夜(GMT时间)的毫秒数,代码如下:
var d1 = new Date(1000000000000); alert(d1); //返回时间对象,如"Sun Sep 9 09 :46 :40 UTC +0800 2001"
创建Date对象之后,就可以调用该对象的各种方法操作时间了。Date对象的方法包括两大类:
- 一类方法是设置时间,如设置时间对象的小时字段setHours(),设置时间对象的月份字段setMonth()等。
- 另一类方法是获取时间对象的各个字段值,如获取时间对象的小时字段getHours(),获取时间对象的月份字段getMonth()等。
【示例5】下面代码使用时间对象的getDay()获取当前时间属于周几。
d = new Date( ); // 获取当前日期和时间 alert(d.toLocaleDateString()); // 显示日期 alert(d.toLocaleTimeString()); // 显示时间 alert(d.getDay()); // 获取一周中的第几天 【示例6】利用Date对象还可以判断两个时间的时差。下面示例可以计算一个循环体空转100万次所花费的毫秒数。 var d1 = new Date(); var i = 0; while(true){ i ++ ; if(i > 1000000) break; } var d2 = new Date(); alert(d2 - d1); // 返回循环体运行的时间
【操作步骤】
第1步,新建文档,保存为index.html,在页面中插入一个表单<form>标签,在其中嵌套一个表格。定义表格7列,2行,其中第1行为合并单元格,第二行为标题行,手动输入一周简称。代码如下所示。
<form name=CLD> <table> <tr class="header"> <td colSpan=7> </td> </tr> <tr> <th>日</td> <th>一</th> <th>二</th> <th>三</th> <th>四</th> <th>五</th> <th>六</th> </tr> </table> </form>
第2步,使用JavaScript代码在Menu组件中动态添加下拉菜单(年)。
<td colSpan=7>公历<select name=SY onchange=changeCld()> <script type="text/javascript"> for(i=1900;i<2050;i++) document.write('<option>'+i); </script> </select>年
第3步,使用JavaScript代码在Menu组件中动态添加下拉菜单(月)。
<select name=SM onchange=changeCld()> <script type="text/javascript"> for(i=1;i<13;i++) document.write('<option>'+i); </script> </select>月 <font id=GZ></font></td>
第4步,使用JavaScript代码在表格中添加6行7列的单元格,代码如下。
<script type="text/javascript"> var gNum; for(i=0;i<6;i++) { document.write('<tr>'); for(j=0;j<7;j++) { gNum = i*7+j; document.write('<td id="GD' + gNum +'"><font id="SD' + gNum +'" '); if(j == 0) document.write(' color=red'); if(j == 6) document.write(' color=blue'); document.write('></font><br><font id="LD' + gNum + '" "></font></td>'); } document.write('</tr>'); } </script>
第5步,下面介绍如何编写用于实现公历日历与农历日历的JavaScript代码。在头部位置插入<script type="text/javascript">标签。
第6步,使用数组记录日历中的相关信息。
var solarMonth=new Array(31,28,31,30,31,30,31,31,30,31,30,31); var Animals=new Array("鼠","牛","虎","兔","龙","蛇","马","羊","猴","鸡","狗","猪"); var solarTerm = new Array("小寒","大寒","立春","雨水","惊蛰","春分","清明","谷雨","立夏","小满","芒种","夏至","小暑","大暑","立秋","处暑","白露","秋分","寒露","霜降","立冬","小雪","大雪","冬至"); var sTermInfo = new Array(0,21208,42467,63836,85337,107014,128867,150921,173149,195551,218072,240693,263343,285989,308563,331033,353350,375494,397447,419210,440795,462224,483532,504758); var nStr1 = new Array('日','一','二','三','四','五','六','七','八','九','十'); var nStr2 = new Array('初','十','廿','卅');
第7步,使用数组保存公历的节日。
//公历节日 var sFtv = new Array( "0101 元旦", "0214 情人节", "0308 妇女节", "0312 植树节", "0315 消费者权益日", "0401 愚人节", "0501 劳动节", "0504 青年节", "0512 护士节", "0601 儿童节", "0701 建党节", "0801 建军节", "0910 教师节", "0928 孔子诞辰", "1001 国庆节", "1006 老人节", "1024 联合国日", "1224 平安夜", "1225 圣诞节")
第8步,使用数组保存农历的节日。
var lFtv = new Array( "0101 春节", "0115 元宵节", "0505 端午节", "0707 七夕情人节", "0715 中元节", "0815 中秋节", "0909 重阳节", "1208 腊八节", "1224 小年")
第9步,自定义函数lYearDays(y),用于返回农历y年的总天数。
function lYearDays(y) { var i, sum = 348; for(i=0x8000; i>0x8; i>>=1)sum+=(lunarInfo[y-1900]&i)?1:0; return(sum+leapDays(y)); }
第10步,自定义函数leapDays(y),用于返回农历y年闰月的天数。
function leapDays(y) { if(leapMonth(y)) return((lunarInfo[y-1900] & 0x10000)? 30: 29); else return(0); }
第11步,自定义函数leapMonth(y),用于判断y年的农历中哪个月是闰月,不是闰月返回0。
function leapMonth(y){ return(lunarInfo[y-1900]&0xf); }
第12步,自定义函数monthDays(y,m),用于返回农历y年m月的总天数。
function monthDays(y,m){ return((lunarInfo[y-1900]&(0x10000>>m))?30:29); }
第13步,自定义函数Dianaday(),用于计算出当前月第一天的农历日期和当前农历日期下一个月农历的第一天日期。
function Dianaday(objDate) { var i, leap=0, temp=0; var baseDate = new Date(1900,0,31); var offset = (objDate - baseDate)/86400000; this.dayCyl = offset+40; this.monCyl = 14; for(i=1900; i<2050 && offset>0; i++) { temp = lYearDays(i) offset -= temp; this.monCyl += 12; } if(offset<0) { offset += temp; i--; this.monCyl -= 12; } this.year = i; this.yearCyl=i-1864; leap = leapMonth(i); //闰哪个月 this.isLeap = false; for(i=1; i<13 && offset>0; i++) { if(leap>0 && i==(leap+1) && this.isLeap==false){ //闰月 --i; this.isLeap = true; temp = leapDays(this.year);} else{ temp = monthDays(this.year, i);} if(this.isLeap==true && i==(leap+1)) this.isLeap = false; //解除闰月 offset -= temp; if(this.isLeap == false) this.monCyl++; } if(offset==0 && leap>0 && i==leap+1) if(this.isLeap){ this.isLeap = false;} else{this.isLeap=true;--i;--this.monCyl;} if(offset<0){offset+=temp;--i;--this.monCyl;} this.month=i; this.day=offset+1; }
第14步,自定义函数solarDays(y,m),用于返回公历y年m+1月的天数。
function solarDays(y,m){ if(m==1) return(((y%4==0)&&(y%100!=0)||(y%400==0))?29:28); else return(solarMonth[m]); }
第15步,自定义函数calElement()用干记录公历和农历某天的日期。
function calElement(sYear,sMonth,sDay,week,lYear,lMonth,lDay,isLeap) { this.isToday = false; //公历 this.sYear = sYear; this.sMonth = sMonth; this.sDay = sDay; this.week = week; //农历 this.lYear = lYear; this.lMonth = lMonth; this.lDay = lDay; this.isLeap = isLeap; //节日记录 this.lunarFestival = ''; //农历节日 this.solarFestival = ''; //公历节日 this.solarTerms = ''; //节气 }
第16步,自定义函数sTerm(y,n)用于返回某年的第n个节气为几日(从小寒算起)。
function sTerm(y,n) { var offDate = new Date((31556925974.7*(y-1900)+sTermInfo[n]*60000)+Date.UTC(1900,0,6,2,5)); return(offDate.getUTCDate()) }
第17步,自定义函数calendar(y,m)用于保存y年m+1月的相关信息。
var fat=mat=9; var eve=0; function calendar(y,m) { fat=mat=0; var sDObj,lDObj,lY,lM,lD=1,lL,lX=0,tmp1,tmp2; var lDPOS = new Array(3); var n = 0; var firstLM = 0; sDObj = new Date(y,m,1); //当月第一天的日期 this.length = solarDays(y,m); //公历当月天数 this.firstWeek = sDObj.getDay(); //公历当月1日星期几 if ((m+1)==5){fat=sDObj.getDay()} if ((m+1)==6){mat=sDObj.getDay()} for(var i=0;i<this.length;i++) { if(lD>lX) { sDObj = new Date(y,m,i+1); //当月第一天的日期 lDObj = new Dianaday(sDObj); //农历 lY = lDObj.year; //农历年 lM = lDObj.month; //农历月 lD = lDObj.day; //农历日 lL = lDObj.isLeap; //农历是否闰月 lX = lL? leapDays(lY): monthDays(lY,lM); //农历当月最後一天 if (lM==12){eve=lX} if(n==0) firstLM = lM; lDPOS[n++] = i-lD+1; } this[i] = new calElement(y,m+1,i+1,nStr1[(i+this.firstWeek)%7],lY,lM,lD++,lL); if((i+this.firstWeek)%7==0){ this[i].color = 'red'; //周日颜色 } } //节气 tmp1=sTerm(y,m*2)-1; tmp2=sTerm(y,m*2+1)-1; this[tmp1].solarTerms = solarTerm[m*2]; this[tmp2].solarTerms = solarTerm[m*2+1]; if((this.firstWeek+12)%7==5) //黑色星期五 this[12].solarFestival += '黑色星期五'; if(y==tY && m==tM) this[tD-1].isToday = true; //今日 }
第18步,自定义函数cDay(d),用中文显示农历的日期。
function cDay(d){ var s; switch (d) { case 10: s = '初十'; break; case 20: s = '二十'; break; break; case 30: s = '三十'; break; break; default : s = nStr2[Math.floor(d/10)]; s += nStr1[d%10]; } return(s); }
第19步,自定义函数drawCld(SY,SM),在表格中显示公历和农历的日期以及相关节日。
var cld; function drawCld(SY,SM) { var TF=true; var p1=p2=""; var i,sD,s,size; cld = new calendar(SY,SM); GZ.innerHTML = ' 【'+Animals[(SY-4)%12]+'】'; //生肖 for(i=0;i<42;i++) { sObj=eval('SD'+ i); lObj=eval('LD'+ i); sObj.className = ''; sD = i - cld.firstWeek; if(sD>-1 && sD<cld.length) { //日期内 sObj.innerHTML = sD+1; if(cld[sD].isToday){ sObj.style.color = '#9900FF';} //今日颜色 else{sObj.style.color = '';} if(cld[sD].lDay==1){ //显示农历月 lObj.innerHTML = '<b>'+(cld[sD].isLeap?'闰':'') + cld[sD].lMonth + '月' + (monthDays(cld[sD].lYear,cld[sD].lMonth)==29?'小':'大')+'</b>'; } else{lObj.innerHTML = cDay(cld[sD].lDay);} //显示农历日 var Slfw=Ssfw=null; s=cld[sD].solarFestival; for (var ipp=0;ipp<lFtv.length;ipp++){ //农历节日 if (parseInt(lFtv[ipp].substr(0,2))==(cld[sD].lMonth)){ if (parseInt(lFtv[ipp].substr(2,4))==(cld[sD].lDay)){ lObj.innerHTML=lFtv[ipp].substr(5); Slfw=lFtv[ipp].substr(5); } } if (12==(cld[sD].lMonth)){ //判断是否为除夕 if (eve==(cld[sD].lDay)){lObj.innerHTML="除夕";Slfw="除夕";} } } for (var ipp=0;ipp<sFtv.length;ipp++){ //公历节日 if (parseInt(sFtv[ipp].substr(0,2))==(SM+1)){ if (parseInt(sFtv[ipp].substr(2,4))==(sD+1)){ lObj.innerHTML=sFtv[ipp].substr(5); Ssfw=sFtv[ipp].substr(5); } } } if ((SM+1)==5){ //母亲节 if (fat==0){ if ((sD+1)==7){Ssfw="母亲节";lObj.innerHTML="母亲节"} } else if (fat<9){ if ((sD+1)==((7-fat)+8)){Ssfw="母亲节";lObj.innerHTML="母亲节"} } } if ((SM+1)==6){ //父亲节 if (mat==0){ if ((sD+1)==14){Ssfw="父亲节";lObj.innerHTML="父亲节"} } else if (mat<9){ if ((sD+1)==((7-mat)+15)){Ssfw="父亲节";lObj.innerHTML="父亲节"} } } if (s.length<=0){ //设置节气的颜色 s=cld[sD].solarTerms; if(s.length>0) s = s.fontcolor('limegreen'); } if(s.length>0) {lObj.innerHTML=s;Slfw=s;} //节气 if ((Slfw!=null)&&(Ssfw!=null)){ lObj.innerHTML=Slfw+"/"+Ssfw; } } else { //非日期 sObj.innerHTML = ''; lObj.innerHTML = ''; } } }
第20步,自定义函数changeCld(),在下拉列表中选择年或月时,调用自定义函数drawCld()显示公历和农历的相关信息。
function changeCld() { var y,m; y=CLD.SY.selectedIndex+1900; m=CLD.SM.selectedIndex; drawCld(y,m); }
第21步,自定义函数initial(),打开网页时,在下拉列表中显示当前年月,并调用自定义函数drawCld(),显示公历和农历的相关信息。
function initial() { CLD.SY.selectedIndex=tY-1900; CLD.SM.selectedIndex=tM; drawCld(tY,tM); }
第22步,在页面初始化完成事件onload中调用自定义函数initial()。
window.onload =function(){ initial(); }