沙发
lanjingquan [专家分:510] 发布于 2003-06-16 12:36:00
发信人: churinga (永远的CS992◎Churinga), 信区: programming
标 题: [合集]万年历算法详解(感谢vivian)
发信站: 一塌糊涂 BBS (Tue Jun 10 15:10:10 2003), 本站(ytht.net)
───────────────────────────────────────
作者 vivian 时间 Tue May 6 01:16:05 2003
───────────────────────────────────────
【 以下文字转载自 vivian 的信箱 】
【 原文由 Aphroditte@smth.edu.cn 所发表 】
发信人: sundew (薇子), 信区: Programming
标 题: Re: 急:请教从公历到农历的转换算法!
发信站: BBS 水木清华站 (Wed Nov 10 21:47:58 1999)
从公历日期推对应干支
一,口诀:
乘五除四九加日,
双月间隔三十天。
一二自加整少一,
三五七八十尾前。
二,举例说明:
例一:1996年1月16日
(96*5+96/4+9+16)/60=8余49,49即为六十甲子序数。9对应天干壬,
49除12余1对应地支子,对应干支为“壬子”。
例二:1997年2月16日
(97*5+97/4+9+16+30+2)/60=9余26,26即为六十甲子序数。6对应天
干己,26除12余2对应地支丑,对应干支为“己丑”。
三,注解:
第三句中的“整少一”,为能被4整除之年一二月份比其他三年都要少
加一;第四句反映的是大月规律,即8月加3、11月加5,依此类推。
【 在 sundew (薇子) 的大作中提到: 】
: 如题。
───────────────────────────────────────
作者 vivian 时间 Tue May 6 01:32:53 2003
───────────────────────────────────────
【 以下文字转载自 vivian 的信箱 】
【 原文由 Aphroditte@smth.edu.cn 所发表 】
发信人: sundew (薇子), 信区: Programming
标 题: Re: 急:请教从公历到农历的转换算法!
发信站: BBS 水木清华站 (Wed Nov 10 21:58:10 1999)
发信人: HIFI (~ZZZ), 信区: program
标 题: Re: 公历和农历的关系!
发信站: 交大兵马俑BBS站 (Sun Jul 11 23:26:28 1999), 转信
【 在 star (光明来到乐) 的大作中提到: 】
: 有这种算法吗?
: 从来没见过
: 有的话我也要一份
: 【 在 ZiXiM (浙客西蒙) 的大作中提到: 】
给你一个delphi的例程:
(我也是抄的,算法就请自己分析了.)
unit CNYear;
interface
uses sysutils;
type TCNDate = Cardinal;
function DecodeGregToCNDate(dtGreg:TDateTime):TCNDate;
function GetGregDateFromCN(cnYear,cnMonth,cnDay:word;bLeap:Boolean=False):
TDateTime;
function GregDateToCNStr(dtGreg:TDateTime):String;
function isCNLeap(cnDate:TCNDate):boolean;
implementation
const cstDateOrg:Integer=32900; //公历1990-01-27的TDateTime表示 对应农历19
90-01-01
const cstCNYearOrg=1990;
const cstCNTable:array[cstCNYearOrg..cstCNYearOrg + 60] of WORD=( //
unsigned 16-bit
24402, 3730, 3366, 13614, 2647, 35542, 858, 1749, //1997
23401, 1865, 1683, 19099, 1323, 2651, 10926, 1386, //2005
32213, 2980, 2889, 23891, 2709, 1325, 17757, 2741, //2013
39850, 1490, 3493, 61098, 3402, 3221, 19102, 1366, //2021
2773, 10970, 1746, 26469, 1829, 1611, 22103, 3243, //2029
1370, 13678, 2902, 48978, 2898, 2853, 60715, 2635, //2037
1195, 21179, 1453, 2922, 11690, 3474, 32421, 3365, //2045
2645, 55901, 1206, 1461, 14038);
//2050
//建表方法:
// 0101 111101010010 高四位是闰月位置,后12位表示大小月,大月30天,小月29
天,
//闰月一般算小月,但是有三个特例2017/06,2036/06,2047/05
//对于特例则高四位的闰月位置表示法中的最高为设置为1 特殊处理用wLeapNormal变
量
// //2017/06 28330->61098 2036/06 27947->60715 2047/05 23133->55901
//如果希望用汇编,这里有一条信息:农历不会滞后公历2个月.
//将公历转换为农历
//返回:12位年份+4位月份+5位日期
function DecodeGregToCNDate(dtGreg:TDateTime):TCNDate;
var
iDayLeave:Integer;
wYear,wMonth,wDay:WORD;
i,j:integer;
wBigSmallDist,wLeap,wCount,wLeapShift:WORD;
label OK;
begin
result := 0;
iDayLeave := Trunc(dtGreg) - cstDateOrg;
DecodeDate(IncMonth(dtGreg,-1),wYear,wMonth,wDay);
if (iDayLeave < 0) or (iDayLeave > 22295 )then Exit;
//Raise Exception.Create('目前只能算1990-01-27以后的');
//Raise Exception.Create('目前只能算2051-02-11以前的');
for i:=Low(cstCNTable) to High(cstCNTable) do begin
wBigSmallDist := cstCNTable[i];
wLeap := wBigSmallDist shr 12;
if wLeap > 12 then begin
wLeap := wLeap and 7;
wLeapShift := 1;
end else
wLeapShift := 0;
for j:=1 to 12 do begin
wCount:=(wBigSmallDist and 1) + 29;
if j=wLeap then wCount := wCount - wLeapShift;
if iDayLeave < wCount then begin
Result := (i shl 9) + (j shl 5) + iDayLeave + 1;
Exit;
end;
iDayLeave := iDayLeave - wCount;
if j=wLeap then begin
wCount:=29 + wLeapShift;
if iDayLeave < wCount then begin
Result := (i shl 9) + (j shl 5) + iDayLeave + 1 + (1 shl
21);
Exit;
end;
iDayLeave := iDayLeave - wCount;
end;
wBigSmallDist := wBigSmallDist shr 1;
end;
end;
//返回值:
// 1位闰月标志 + 12位年份+4位月份+5位日期 (共22位)
end;
function isCNLeap(cnDate:TCNDate):boolean;
begin
result := (cnDate and $200000) <> 0;
end;
function GetGregDateFromCN(cnYear,cnMonth,cnDay:word;bLeap:Boolean=False):
TDateTime;
var
i,j:integer;
DayCount:integer;
wBigSmallDist,wLeap,wLeapShift:WORD;
begin
// 0101 010010101111 高四位是闰月位置,后12位表示大小月,大月30天,小月
29天,
DayCount := 0;
if (cnYear < 1990) or (cnYear >2050) then begin
Result := 0;
Exit;
end;
for i:= cstCNYearOrg to cnYear-1 do begin
wBigSmallDist := cstCNTable[i];
if (wBIgSmallDist and $F000) <> 0 then DayCount := DayCount + 29;
DayCount := DayCount + 12 * 29;
for j:= 1 to 12 do begin
DayCount := DayCount + wBigSmallDist and 1;
wBigSmallDist := wBigSmallDist shr 1;
end;
end;
wBigSmallDist := cstCNTable[cnYear];
wLeap := wBigSmallDist shr 12;
if wLeap > 12 then begin
wLeap := wLeap and 7;
wLeapShift := 1; //大月在闰月.
end else
wLeapShift := 0;
for j:= 1 to cnMonth-1 do begin
DayCount:=DayCount + (wBigSmallDist and 1) + 29;
if j=wLeap then DayCount := DayCount + 29;
wBigSmallDist := wBigSmallDist shr 1;
end;
if bLeap and (cnMonth = wLeap) then //是要闰月的吗?
DayCount := DayCount + 30 - wLeapShift;
result := cstDateOrg + DayCount + cnDay - 1;
end;
//将日期显示成农历字符串.
function GregDateToCNStr(dtGreg:TDateTime):String;
const hzNumber:array[0..10] of string=('零','一','二','三','四','五','六',
'七','八','九','十');
function ConvertYMD(Number:Word;YMD:Word):string;
var
wTmp:word;
begin
result := '';
if YMD = 1 then begin //年份
while Number > 0 do begin
result := hzNumber[Number Mod 10] + result;
Number := Number DIV 10;
end;
Exit;
end;
if Number<=10 then begin //可只用1位
if YMD = 2 then //月份
result := hzNumber[Number]
else //天
result := '初' + hzNumber[Number];
Exit;
end;
wTmp := Number Mod 10; //个位
if wTmp <> 0 then result := hzNumber[wTmp];
wTmp := Number Div 10; //十位
result:='十'+result;
if wTmp > 1 then result := hzNumber[wTmp] + result;
end;
var
cnYear,cnMonth,cnDay:word;
cnDate:TCNDate;
strLeap:string;
begin
cnDate:= DecodeGregToCNDate(dtGreg);
if cnDate = 0 then begin
result := '输入越界';
Exit;
end;
cnDay := cnDate and $1F;
cnMonth := (cnDate shr 5) and $F;
cnYear := (cnDate shr 9) and $FFF;
//测试第22位,为1表示闰月
if isCNLeap(cnDate) then strLeap:='(闰)' else strLeap := '';
result := '农历' + ConvertYMD(cnYear,1) + '年' + ConvertYMD(cnMonth,2) +
'月'
+ strLeap + ConvertYMD(cnDay,3) ;
end;
end.
───────────────────────────────────────
作者 vivian 时间 Tue May 6 01:33:01 2003
───────────────────────────────────────
【 以下文字转载自 vivian 的信箱 】
【 原文由 Aphroditte@smth.edu.cn 所发表 】
发信人: peach (呆呆), 信区: Programming
标 题: Re: 请问万年历的算法!!
发信站: BBS 水木清华站 (Fri Jun 14 19:22:10 2002)
最关键的是jdnum和initfromjd两个函数
如果想知道怎么回事,请查天文学上的儒略历
#ifndef _SPUTIL_TIME_H_INC_
#define _SPUTIL_TIME_H_INC_
// 4786 调试符号长度超过255个字符
// 4530 C++ Exception catch
#pragma warning(disable:4786 4530)
#include <sputil/sputildef.h>
#include <time.h>
nsbegin(spu);
class time {
private:
// year, month, day, seconds;
spu::word y; // 1 ~ 65535
spu::byte m, d; // m: 1 ~ 12, d: 1 ~ 31
int s; // seconds in one day 0 ~ 86399
public:
time () : y(1), m(1), d(1), s(0) {
}
time (int year, int month, int day, int seconds=0) : y(year), m(month),
d(day), s(seconds){
};
time (int jd, int seconds=0) : s(seconds){
initfromjd(jd);
}
time (time_t tm) {
s = tm%86400;
initfromjd(2440588 + tm/86400);
}
time (__int64 i64) {
i64/=10000000;
i64 -= 11644473600;
s = (int)(i64%86400);
initfromjd(2440588 + (int)(i64/86400));
}
#ifdef _WIN32
time (const FILETIME* pft) {
__int64 i64 = *(__int64*)pft;
i64/=10000000;
i64 -= 11644473600;
s = (int)(i64%86400);
initfromjd(2440588 + (int)(i64/86400));
}
time (const SYSTEMTIME* pst) {
y = pst->wYear;
m = (spu::byte)pst->wMonth;
d = (spu::byte)pst->wDay;
s = pst->wHour*3600 + pst->wMinute*60 + pst->wSecond;
}
time (const FILETIME& ft) {
*this = time(&ft);
}
time (const SYSTEMTIME& st) {
*this = time(&st);
}
#endif
int getyear () const {
return y;
}
int getmonth () const {
return m;
}
int getday () const {
return d;
}
int gethour () const {
return s/3600;
}
int getminute () const {
return s%3600/60;
}
int getsecond () const {
return s%60;
}
int gets () const {
return s;
}
time_t get_time_t () const {
// 未作溢出检查
return (jdnum () - 2440588)*86400 + s;
}
__int64 ftime() const {
return (__int64)jdnum ()*86400+s;
}
int dayofweek() const {
return (jdnum ()+1)%7;
}
int setyear (int year) {
return y = year;
}
int setmonth (int month) {
return m = month;
}
int setday (int day) {
return d = day;
}
int sethour (int h) {
h %= 24;
s = s%3600 + h *3600;
return h;
}
int setminute (int m) {
m %= 60;
s = s/3600*3600 + s%60 + m*60;
return m;
}
int setsecond (int sec) {
sec %= 60;
s = s/60*60 + sec;
return s;
}
int sets (int s) {
this->s = s;
return s;
}
int jdnum () const {
int a = (m-14)/12;
return (1461*(y+4800+a))/4
+ (367*(m-2-12*(a)))/12
- (3*((y+4900+a)/100))/4
+ d-32075;
}
void initfromjd (int jdnum) {
int i, j, l, n;
l = jdnum + 68569;
n = ( 4 * l ) / 146097;
l = l - ( 146097 * n + 3 ) / 4;
i = ( 4000 * ( l + 1 ) ) / 1461001;
l = l - ( 1461 * i ) / 4 + 31;
j = ( 80 * l ) / 2447;
d = l - ( 2447 * j ) / 80;
l = j / 11;
m = j + 2 - ( 12 * l );
y = 100 * ( n - 49 ) + i + l;
}
time& add (int days, int seconds = 0) {
s += seconds;
while(s < 0){
s += 86400;
days --;
};
while(s >= 86400){
days += s/86400;
s %= 86400;
}
initfromjd (jdnum () + days);
return *this;
}
time& operator += (int sec) {
add(sec/86400, sec%86400);
return *this;
}
time operator + (int sec) const {
return time(*this) += sec;
}
time& operator -= (int sec) {
return operator += (-sec);
}
3 楼
lanjingquan [专家分:510] 发布于 2003-06-16 12:40:00
<html>
<head>
<body>
<SCRIPT language=JavaScript>
<!--
/***********************************************************************
******
日期资料
************************************************************************
*****/
var lunarInfo=new Array(
0x04bd8,0x04ae0,0x0a570,0x054d5,0x0d260,0x0d950,0x16554,0x056a0,
0x09ad0,0x055d2,
0x04ae0,0x0a5b6,0x0a4d0,0x0d250,0x1d255,0x0b540,0x0d6a0,0x0ada2,
0x095b0,0x14977,
0x04970,0x0a4b0,0x0b4b5,0x06a50,0x06d40,0x1ab54,0x02b60,0x09570,
0x052f2,0x04970,
0x06566,0x0d4a0,0x0ea50,0x06e95,0x05ad0,0x02b60,0x186e3,0x092e0,
0x1c8d7,0x0c950,
0x0d4a0,0x1d8a6,0x0b550,0x056a0,0x1a5b4,0x025d0,0x092d0,0x0d2b2,
0x0a950,0x0b557,
0x06ca0,0x0b550,0x15355,0x04da0,0x0a5d0,0x14573,0x052d0,0x0a9a8,
0x0e950,0x06aa0,
0x0aea6,0x0ab50,0x04b60,0x0aae4,0x0a570,0x05260,0x0f263,0x0d950,
0x05b57,0x056a0,
0x096d0,0x04dd5,0x04ad0,0x0a4d0,0x0d4d4,0x0d250,0x0d558,0x0b540,
0x0b5a0,0x195a6,
0x095b0,0x049b0,0x0a974,0x0a4b0,0x0b27a,0x06a50,0x06d40,0x0af46,
0x0ab60,0x09570,
0x04af5,0x04970,0x064b0,0x074a3,0x0ea50,0x06b58,0x055c0,0x0ab60,
0x096d5,0x092e0,
0x0c960,0x0d954,0x0d4a0,0x0da50,0x07552,0x056a0,0x0abb7,0x025d0,
0x092d0,0x0cab5,
0x0a950,0x0b4a0,0x0baa4,0x0ad50,0x055d9,0x04ba0,0x0a5b0,0x15176,
0x052b0,0x0a930,
0x07954,0x06aa0,0x0ad50,0x05b52,0x04b60,0x0a6e6,0x0a4e0,0x0d260,
0x0ea65,0x0d530,
0x05aa0,0x076a3,0x096d0,0x04bd7,0x04ad0,0x0a4d0,0x1d0b6,0x0d250,
0x0d520,0x0dd45,
0x0b5a0,0x056d0,0x055b2,0x049b0,0x0a577,0x0a4b0,0x0aa50,0x1b255,
0x06d20,0x0ada0)
var solarMonth=new Array(31,28,31,30,31,30,31,31,30,31,30,31);
var Gan=new Array("甲","乙","丙","丁","戊","己","庚","辛","壬","癸");
var Zhi=new Array("子","丑","寅","卯","辰","巳","午","未","申","酉","戌
","亥");
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('初','十','廿','卅',' ')
var monthName = new Array("JAN","FEB","MAR","APR","MAY","JUN","JUL",
"AUG","SEP","OCT","NOV","DEC");
//国历节日 *表示放假日
var sFtv = new Array(
"0101*元旦",
"0214 情人节",
"0308 妇女节",
"0312 植树节",
"0315 消费者权益日",
"0317 St. Patrick's",
"0401 愚人节",
"0501*劳动节",
"0504 青年节",
"0512 护士节",
"0512 茵生日",
"0601 儿童节",
"0614 Flag Day",
"0701 建党节 香港回归日",
"0703 炎黄在线诞辰",
"0718 托普诞辰",
"0801 建军节",
"0808 父亲节",
"0909 毛泽东逝世纪念",
"0910 教师节",
"0928 孔子诞辰",
"1001*国庆节",
"1006 老人节",
"1015 My Birthday^_^",
"1024 联合国日",
"1111 Veteran's / Remembrance Day",
"1112 孙中山诞辰",
"1220 澳门回归纪念",
"1225 Christmas Day",
"1226 毛泽东诞辰")
//农历节日 *表示放假日
var lFtv = new Array(
"0101*春节",
"0115 元宵节",
"0505 端午节",
"0707 七夕情人节",
"0715 中元节",
"0815 中秋节",
"0909 重阳节",
"1208 腊八节",
"1224 小年",
"0100*除夕")
//某月的第几个星期几
var wFtv = new Array(
"0131 Martin Luther King Day",
"0231 President's Day",
"0520 母亲节",
"0530 Armed Forces Day",
"0531 Victoria Day",
"0716 合作节",
"0730 被奴役国家周",
"0811 Civic Holiday",
"0911 Labor Holiday",
"1021 Columbus Day",
"1144 Thanksgiving")
/***********************************************************************
******
日期计算
************************************************************************
*****/
//====================================== 传回农历 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))
}
//====================================== 传回农历 y年闰月的天数
function leapDays(y) {
if(leapMonth(y)) return((lunarInfo[y-1900] & 0x10000)? 30: 29)
else return(0)
}
//====================================== 传回农历 y年闰哪个月 1-12 , 没
闰传回 0
function leapMonth(y) {
return(lunarInfo[y-1900] & 0xf)
}
//====================================== 传回农历 y年m月的总天数
function monthDays(y,m) {
return( (lunarInfo[y-1900] & (0x10000>>m))? 30: 29 )
}
//====================================== 算出农历, 传入日期物件, 传回农
历日期物件
// 该物件属性有 .year .month .
day .isLeap .yearCyl .dayCyl .monCyl
function Lunar(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
}
//==============================传回国历 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])
}
//============================== 传入 offset 传回干支, 0=甲子
function cyclical(num) {
return(Gan[num%10]+Zhi[num%12])
}
//============================== 月历属性
function calElement(sYear,sMonth,sDay,week,lYear,lMonth,lDay,isLeap,
cYear,cMonth,cDay) {
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.cYear = cYear;
this.cMonth = cMonth;
this.cDay = cDay;
this.color = '';
this.lunarFestival = ''; //农历节日
this.solarFestival = ''; //国历节日
this.solarTerms = ''; //节气
}
//===== 某年的第n个节气为几日(从0小寒起算)
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())
}
//============================== 传回月历物件 (y年,m+1月)
function calendar(y,m) {
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日星期几
for(var i=0;i<this.length;i++) {
if(lD>lX) {
sDObj = new Date(y,m,i+1) //当月一日日期
lDObj = new Lunar(sDObj) //农历
lY = lDObj.year //农历年
lM = lDObj.month //农历月
lD = lDObj.day //农历日
lL = lDObj.isLeap //农历是否闰月
lX = lL? leapDays(lY): monthDays(lY,lM) //农历当月最後一天
if(n==0) firstLM = lM
lDPOS[n++] = i-lD+1
}
//sYear,sMonth,sDay,week,
//lYear,lMonth,lDay,isLeap,
//cYear,cMonth,cDay
this[i] = new calElement(y, m+1, i+1, nStr1[(i+this.
firstWeek)%7],
lY, lM, lD++, lL,
cyclical(lDObj.yearCyl) ,cyclical(lDObj.
monCyl), cyclical(lDObj.dayCyl++) )
if((i+this.firstWeek)%7==0) this[i].color = 'red' //周日颜色
if((i+this.firstWeek)%14==13) 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(m==3) this[tmp1].color = 'red' //清明颜色
//国历节日
for(i in sFtv)
if(sFtv[i].match(/^(\d{2})(\d{2})([\s\*])(.+)$/))
if(Number(RegExp.$1)==(m+1)) {
this[Number(RegExp.$2)-1].solarFestival += RegExp.$4 + ' '
if(RegExp.$3=='*') this[Number(RegExp.$2)-1].color = 'red'
}
//月周节日
for(i in wFtv)
if(wFtv[i].match(/^(\d{2})(\d)(\d)([\s\*])(.+)$/))
if(Number(RegExp.$1)==(m+1)) {
tmp1=Number(RegExp.$2)
tmp2=Number(RegExp.$3)
this[((this.firstWeek>tmp2)?7:0) + 7*(tmp1-1) + tmp2 -
this.firstWeek].solarFestival += RegExp.$5 + ' '
}
//农历节日
for(i in lFtv)
if(lFtv[i].match(/^(\d{2})(.{2})([\s\*])(.+)$/)) {
tmp1=Number(RegExp.$1)-firstLM
if(tmp1==-11) tmp1=1
if(tmp1 >=0 && tmp1<n) {
tmp2 = lDPOS[tmp1] + Number(RegExp.$2) -1
if( tmp2 >= 0 && tmp2<this.length) {
this[tmp2].lunarFestival += RegExp.$4 + ' '
if(RegExp.$3=='*') this[tmp2].color = 'red'
}
}
}
//黑色星期五
if((this.firstWeek+12)%7==5)
this[12].solarFestival += '黑色星期五 '
//今日
if(y==tY && m==tM) this[tD-1].isToday = true;
}
//====================== 中文日期