📄 lunar.js
字号:
if(v<600 || v >86400-600) t = XL.S_aLon_t(W)*36525 - JD.deltatT2(t);
return t + 8/24;
}
function suo_high(W){ //较高精度朔
var t = XL.MS_aLon_t2(W)*36525;
t = t - JD.deltatT2(t);
var v = ( (t+0.5) %1 ) * 86400;
if(v<600 || v >86400-600) t = XL.MS_aLon_t(W)*36525 - JD.deltatT2(t);
return t + 8/24;
}
function getQS1(jd,qs){ //jd应靠近所要取得的气朔日,qs='气'时,算节气的儒略日
jd += 2451545;
var i,D,n;
var B=suoKB,pc=14; if(qs=='气') B=qiKB,pc=7;
var f1=B[0]-pc, f2=B[B.length-1]-pc, f3=2436935;
if( jd<f1 || jd>=f3 ){ //平气朔表中首个之前,使用现代天文算法。1960.1.1以后,使用现代天文算法
if(qs=='气') return Math.floor( qi_high ( Math.floor((jd+pc-2451259)/365.2422*24) * Math.PI/12 ) +0.5 ); //2451259是1999.3.21,太阳视黄经为0,春分.定气计算
else return Math.floor( suo_high( Math.floor((jd+pc-2451551)/29.5306) * Math.PI*2 ) +0.5 ); //2451551是2000.1.7的那个朔日,黄经差为0.定朔计算
}
if( jd>=f1 && jd<f2 ) { //平气或平朔
for(i=0;i<B.length;i+=2) if(jd+pc<B[i+2]) break;
D = B[i] + B[i+1] * Math.floor( (jd+pc-B[i])/B[i+1] );
D = Math.floor(D+0.5);
if(D==1683460) D++; //如果使用太初历计算-103年1月24日的朔日,结果得到的是23日,这里修正为24日(实历)。修正后仍不影响-103的无中置闰。如果使用秦汉历,得到的是24日,本行D不会被执行。
return D-2451545;;
}
if( jd>=f2 && jd<f3){ //定气或定朔
if(qs=='气'){
D = Math.floor( qi_low( Math.floor((jd+pc-2451259)/365.2422*24) * Math.PI/12 ) +0.5 ); //2451259是1999.3.21,太阳视黄经为0,春分.定气计算
n = qiS.substr( Math.floor((jd-f2)/365.2422*24),1 ); //找定气修正值
}else{
D = Math.floor( suo_low( Math.floor((jd+pc-2451551)/29.5306) * Math.PI*2 ) +0.5 ); //2451551是2000.1.7的那个朔日,黄经差为0.定朔计算
n = suoS.substr( Math.floor((jd-f2)/29.5306),1 ); //找定朔修正值
}
if(n=="1") return D+1;
if(n=="2") return D-1;
return D;
}
}
//===============气朔时刻精算=======================
function qi_accurate(W) { var t=XL.S_aLon_t(W)*36525; return t - JD.deltatT2(t) + 8/24; } //精气
function suo_accurate(W) { var t=XL.MS_aLon_t(W)*36525; return t - JD.deltatT2(t) + 8/24; } //精朔
function qi_accurate2(jd) { return qi_accurate ( Math.floor((jd+293)/365.2422*24) * Math.PI/12 ); } //精气
function suo_accurate2(jd) { return suo_accurate ( Math.floor((jd+8)/29.5306) * Math.PI*2 ); } //精朔
Lunar={
Gan:new Array("甲","乙","丙","丁","戊","己","庚","辛","壬","癸"),
Zhi:new Array("子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥"),
ShX:new Array("鼠","牛","虎","兔","龙","蛇","马","羊","猴","鸡","狗","猪"),
XiZ:new Array('摩羯','水瓶','双鱼','白羊','金牛','双子','巨蟹','狮子','处女','天秤','天蝎','射手'),
yxmc:new Array("朔","上弦","望","下弦"), //月相名称表
jqmc:new Array('冬至','小寒','大寒','立春','雨水','惊蛰','春分','清明','谷雨','立夏','小满','芒种','夏至','小暑','大暑','立秋','处暑','白露','秋分','寒露','霜降','立冬','小雪','大雪'),
ymc:new Array('十一','十二','正','二','三','四','五','六','七','八','九','十'), //月名称,建寅
rmc:new Array('初一','初二','初三','初四','初五','初六','初七','初八','初九','初十','十一','十二','十三','十四','十五','十六','十七','十八','十九','二十','廿一','廿二','廿三','廿四','廿五','廿六','廿七','廿八','廿九','三十','三一'),
Weeks:new Array('日','一','二','三','四','五','六','七','八','九','十'),
//在调用calc()或calc2()后得到以下数据
leap:0, //闰月位置
ym:new Array(), //各月名称
ZQ:new Array(), //中气表,其中.liqiu是节气立秋的儒略日,计算三伏时用到
HS:new Array(), //合朔表
dx:new Array(), //各月大小
nu:new Array(), //闰月情况
lun:new Array(),//月历数组,在调用calc2()之后得到
calc:function(jd){ //农历排月序计算,可定出农历,有效范围:两个冬至之间(冬至一 <= d < 冬至二)
var A=this.ZQ, B=this.HS; //中气表,日月合朔表(整日)
var i, k, W, w;
//该年的中气
W = int2( (jd-355+183)/365.2422 )*365.2422+355; //355是2000.12冬至,得到较靠近jd的冬至估计值
if(getQS1(W,'气')>jd) W-=365.2422;
for(i=0;i<25;i++) A[i]=getQS1(W+15.2184*i,'气'); //25个节气时刻(北京时间),从冬至开始到下一个冬至以后
A.mangzhong=A[11], A.xiaoshu=A[13], A.liqiu=A[15], A.lichun=A[3]; //保存芒种,小暑,立秋,立春
//今年"首朔"的日月黄经差w
w = getQS1(A[0],'朔'); //求较靠近冬至的朔日
if(w>A[0]) w -= 29.53;
//该年所有朔,包含14个月的始末
for(i=0;i<15;i++) B[i]=getQS1(w+29.5306*i,'朔');
//月大小
this.leap = 0;
for(i=0;i<14;i++){
this.dx[i] = this.HS[i+1]-this.HS[i]; //月大小
this.ym[i]=i; //月序初始化
this.nu[i]=''; //闰初始化
}
//-721年至-104年的后九月及月建问题,与朔有关,与气无关
var YY = int2( (this.ZQ[0]+10 +180)/365.2422) + 2000; //确定年份
if( YY>=-721 && YY <=-104 ){
var ly,b0,k0,lName,x0; //ly为历元(本历首月的儒略数),x0月建,lName闰月名称,b0,k0为置闰拟合参数
if(YY>=-721) ly=1457698-J2000, k0=12.368422, b0=0.342, lName='十三', x0=2; //春秋历,ly为-722.12.17
if(YY>=-479) ly=1546083-J2000, k0=12.368422, b0=0.500, lName='十三', x0=2; //战国历,ly为-480.12.11
if(YY>=-220) ly=1640641-J2000, k0=12.369000, b0=0.866, lName='后九', x0=11; //秦汉历,ly为-221.10.31;
nY = int2( (this.HS[0]-ly+100)/365.25 ); //年积数
var f1 = int2(b0+nY*k0), f2 = int2(b0+nY*k0+k0), f3; //f1有本年首的月积数,f2为下一年首的月积数
f1 = int2(f1); f2 = int2(f2);
for(i=0;i<14;i++){
f3 = int2( (this.HS[i]-ly+15)/29.5306 ); //该月积数
if(f3 < f2) f3 -= f1; else f3 -= f2;
if(f3 < 12) this.ym[i] = this.ymc[(f3+x0)%12]; else this.ym[i] = lName;
}
return;
}
//无中气置闰法确定闰月,(气朔结合法,数据源需有冬至开始的的气和朔)
if( B[13] <= A[24] ){ //第13月的月末没有超过冬至(不含冬至),说明今年含有13个月
for(i=1; B[i+1]>A[2*i] && i<13; i++); //在13个月中找第1个没有中气的月份
this.leap = i;
for(;i<14;i++) this.ym[i]--;
}
//名称转换(月建别名)
for(i=0;i<14;i++){
var Dm = this.HS[i]+J2000, v2=this.ym[i]; //Dm初一的儒略日,v2为月建序号
var mc = this.ymc[v2%12]; //月建对应的默认月名称:建子十一,建丑十二,建寅为正……
if ( Dm>=1724360 && Dm<=1729794 ) mc = this.ymc[(v2+1)%12]; // 8.01.15至 23.12.02 建子为十二,其它顺推
else if( Dm>=1807724 && Dm<=1808699 ) mc = this.ymc[(v2+1)%12]; //237.04.12至239.12.13 建子为十二,其它顺推
else if( Dm>=1999349 && Dm<=1999467 ) mc = this.ymc[(v2+2)%12]; //761.12.02至762.03.30 建子为正月,其它顺推
else if( Dm>=1973067 && Dm<=1977112 ){if(v2%12==0) mc="正"; if(v2==2) mc='一';} //689.12.18至701.01.14 建子为正月,建寅为一月,其它不变
if(Dm==1729794||Dm==1808699) mc='拾贰'; //239.12.13及23.12.02均为十二月,为避免两个连续十二月,此处改名
this.ym[i]=mc;
if((i==this.leap) && i) this.nu[i]='闰'; else this.nu[i]='';
}
},
calc2:function(By,Bm,sw){ //返回公历某一个月的'公农回'三合历
var i,j,k,c,Bd0,Bdn,lun=this.lun;
if(!this.lun.length) { for(var i=0;i<31;i++) this.lun[i] = new Array(); }
//日历物件初始化
JD.h=12, JD.m=0, JD.s=0.1;
JD.Y=By; JD.M=Bm; JD.D=1; Bd0 = int2(JD.toJD()) - J2000; //公历月首,中午
JD.M++; if(JD.M>12) JD.Y++,JD.M=1; Bdn = int2(JD.toJD()) - J2000 - Bd0; //本月天数(公历)
lun.w0= (Bd0 + J2000 +1)%7; //本月第一天的星期
lun.y = By; //公历年份
lun.m = Bm; //公历月分
lun.d0 =Bd0;
lun.dn= Bdn;
//所属公历年对应的农历干支纪年
c = int2((Bd0-Bm*30+150)/365.2422) + 16 + 9000;
lun.Ly = Lunar.Gan[c%10]+Lunar.Zhi[c%12]; //干支纪年
lun.ShX = Lunar.ShX[c%12]; //该年对应的生肖
//年号纪年处理
lun.nianhao = new getNH(lun.y);
var D,w,ob,ob2;
//提取各日信息
for(i=0,j=0;i<Bdn;i++){
ob = lun[i];
ob.d0 = Bd0+i; //儒略日,北京时12:00
ob.di = i; //公历月内日序数
ob.y = By; //公历年
ob.m = Bm; //公历月
ob.dn = Bdn; //公历月天数
ob.week0 = lun.w0; //月首的星期
ob.week = (lun.w0+i)%7; //当前日的星期
ob.weeki = int2((lun.w0+i)/7); //本日所在的周序号
ob.weekN = int2((lun.w0+Bdn-1)/7) + 1; //本月的总周数
JD.setFromJD(ob.d0+J2000); ob.d = JD.D; //公历日名称
//农历月历
if(!this.ZQ.length || ob.d0<this.ZQ[0] || ob.d0>=this.ZQ[24]) //如果d0已在计算农历范围内则不再计算
this.calc(ob.d0);
var mk = int2( (ob.d0-this.HS[0])/30 ); if(mk<13 && this.HS[mk+1]<=ob.d0) mk++; //农历所在月的序数
ob.Ldi = ob.d0 - this.HS[mk]; //距农历月首的编移量,0对应初一
ob.Ldc = this.rmc[ob.Ldi]; //农历日名称
ob.cur_dz = ob.d0-this.ZQ[0]; //距冬至的天数
ob.cur_xz = ob.d0-this.ZQ[12]; //距夏至的天数
ob.cur_lq = ob.d0-this.ZQ.liqiu;//距立秋的天数
ob.cur_mz = ob.d0-this.ZQ.mangzhong;//距芒种的天数
ob.cur_xs = ob.d0-this.ZQ.xiaoshu; //距小暑的天数
if(ob.d0==this.HS[mk]||ob.d0==Bd0){ //月的信息
ob.Lmc = this.ym[mk]; //月名称
ob.Ldn = this.dx[mk]; //月大小
ob.Lleap= this.nu[mk]; //闰状况
ob.Lmc2 = mk<13?this.ym[mk+1]:"未知"; //下个月名称,判断除夕时要用到
}else{
ob2=this.lun[i-1];
ob.Lmc = ob2.Lmc, ob.Ldn = ob2.Ldn;
ob.Lleap= ob2.Lleap, ob.Lmc2 = ob2.Lmc2;
}
var qk=int2( (ob.d0-this.ZQ[0]-7)/15.2184 ); if(qk<23 && ob.d0>=this.ZQ[qk+1]) qk++; //节气的取值范围是0-23
if(ob.d0==this.ZQ[qk]) ob.Ljq=this.jqmc[qk];
else ob.Ljq='';
ob.yxmc = ob.yxjd = ob.yxsj ='';//月相名称,月相时刻(儒略日),月相时间串
ob.jqmc = ob.jqjd = ob.jqsj ='';//定气名称,节气时刻(儒略日),节气时间串
//干支纪年处理
//以下被注释的两行以正月初一定年首
//for(j=mk;j>=0;j--) if(this.ym[j]=="正月") break;
//D=j<0 ? this.HS[2]-365 : this.HS[j]+5810; //该年春节与1984年平均春节(立春附近)相差天数估计
D = this.ZQ.lichun + (ob.d0<this.ZQ.lichun?-365:0) + 365.25*16-35; //以立春为界定纪年
ob.Lyear = Math.floor(D/365.2422+0.5); //农历纪年(10进制,1984年起算)
D = ob.Lyear +9000;
ob.Lyear2 = this.Gan[D%10]+this.Zhi[D%12]; //干支纪年
//纪月处理,1998年12月7(大雪)开始连续进行节气计数,0为甲子
mk = int2( (ob.d0 - this.ZQ[0])/30.43685 ); if(mk<12 && ob.d0>=this.ZQ[2*mk+1]) mk++; //相对大雪的月数计算,mk的取值范围0-12
D = mk + int2( (this.ZQ[12]+390)/365.2422 )*12 + 900000; //相对于1998年12月7(大雪)的月数,900000为正数基数
ob.Lmonth = D%12;
ob.Lmonth2 = this.Gan[D%10]+this.Zhi[D%12];
//纪日,2000年1月7日起算
D = (ob.d0 - 6 + 9000000)%60;
ob.Lday2 = this.Gan[D%10]+this.Zhi[D%12];
//纪时,2000年1月2日起算
D = (ob.d0 - 1)*12 + 90000000;
for(k=0,c='';k<12;k++){
w = (k*2+23)%24; if(w<10) w='0'+w; c+=w+'-';
w = k*2+1; if(w<10) w='0'+w; c+=w;
c += this.Gan[(D+k)%10]+this.Zhi[(D+k)%12]+'时 ';
if(k%3==2) c+='<br>';
}
ob.Ltime2=c;
//节日
this.getDayName(ob);
//星座
mk = int2( (ob.d0-this.ZQ[0]-15)/30.43685 ); if( mk<11 && ob.d0>=this.ZQ[2*mk+2] ) mk++; //星座所在月的序数,(如果j=13,ob.d0不会超过第14号中气)
ob.XiZ = this.XiZ[(mk+12)%12]+'座';
//回历
this.getHuiLi(ob);
}
//以下是月相与节气的处理
if(!sw) return;
var d, xn, jd2= Bd0+JD.deltatT2(Bd0)-8/24;
//月相查找
w = XL.MS_aLon( jd2/36525,10,3 );
w = int2( (w-0.78)/Math.PI*2 ) * Math.PI/2;
do {
d = suo_accurate(w);
D = int2(d+0.5);
xn = int2(w/pi2*4+4000000.01)%4;
w += pi2/4;
if(D>=Bd0+Bdn) break;
if(D<Bd0) continue;
ob = this.lun[D-Bd0];
ob.yxmc = this.yxmc[xn]; //取得月相名称
ob.yxjd = d;
ob.yxsj = JD.timeStr(d);
} while(D+5<Bd0+Bdn);
//节气查找
w = XL.S_aLon( jd2/36525, 3 );
w = int2( (w-0.13)/pi2*24 ) *pi2/24;
do {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -