;(function() { var root = this; /////////////////////////////////////////////////// // // lunarInfo // /////////////////////////////////////////////////// // base data about chinese year informace // ä¿å˜å…¬åŽ†å†œåŽ†ä¹‹é—´çš„è½¬æ¢ä¿¡æ¯:以任æ„一年作为起点, // 把从这一年起若干年(ä¾éœ€è¦è€Œå®š)的农历信æ¯ä¿å˜èµ·æ¥ã€‚ è¦ä¿å˜ä¸€å¹´çš„ä¿¡æ¯ï¼Œåªè¦ä¸¤ä¸ªä¿¡æ¯å°±å¤Ÿäº†: 1)农历æ¯ä¸ªæœˆçš„大å°;2)ä»Šå¹´æ˜¯å¦æœ‰é—°æœˆï¼Œé—°å‡ 月以åŠé—°æœˆçš„大å°ã€‚ 用一个整数æ¥ä¿å˜è¿™äº›ä¿¡æ¯å°±è¶³å¤Ÿäº†ã€‚ 具体的方法是:ç”¨ä¸€ä½æ¥è¡¨ç¤ºä¸€ä¸ªæœˆçš„大å°ï¼Œå¤§æœˆè®°ä¸º1ï¼Œå°æœˆè®°ä¸º0, // è¿™æ ·å°±ç”¨æŽ‰12ä½(æ— é—°æœˆ)或13ä½(有闰月),å†ç”¨é«˜å››ä½æ¥è¡¨ç¤ºé—°æœˆçš„æœˆä»½ï¼Œæ²¡æœ‰é—°æœˆè®°ä¸º0。 ※-----例----: 2000å¹´çš„ä¿¡æ¯æ•°æ®æ˜¯0xc96,化æˆäºŒè¿›åˆ¶å°±æ˜¯110010010110B, // 表示的å«ä¹‰æ˜¯:1ã€2ã€5ã€8ã€10ã€11月大,其余月份å°ã€‚ 2001å¹´çš„å†œåŽ†ä¿¡æ¯æ•°æ®æ˜¯0x1a95(å› ä¸ºé—°æœˆï¼Œæ‰€ä»¥æœ‰13ä½), // 具体的就是1ã€2ã€4ã€5ã€8ã€10ã€12月大, 其余月份å°(0x1a95=1101010010101B), // 4月的åŽé¢é‚£ä¸€ä¸ª0表示的是闰4月å°ï¼ŒæŽ¥ç€çš„那个1表示5月大。 è¿™æ ·å°±å¯ä»¥ç”¨ä¸€ä¸ªæ•°ç»„æ¥ä¿å˜è¿™äº›ä¿¡æ¯ã€‚在这里用数组lunarInfo[]æ¥ä¿å˜è¿™äº›ä¿¡æ¯ 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 Gan=new Array("甲","ä¹™","丙","ä¸","戊","å·±","庚","è¾›","壬","癸"); var Zhi=new Array("å","丑","寅","å¯","è¾°","å·³","åˆ","未","申","é…‰","戌","亥"); var Animals=new Array("é¼ ","牛","虎","å…”","é¾™","蛇","马","羊","猴","鸡","ç‹—","猪"); // TODO is it need to do 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 cmonthName = new Array('æ£','二','三','å››','五','å…','七','å…«','ä¹','å','å一','è…Š'); //公历节日 *è¡¨ç¤ºæ”¾å‡æ—¥ var sFtv = new Array( "0101*元旦", "0214 情人节", "0308 妇女节", "0312 æ¤æ ‘节", "0401 愚人节", "0422 åœ°çƒæ—¥", "0501 劳动节", "0504 é’年节", "0531 æ— çƒŸæ—¥", "0601 儿童节", "0606 爱眼日", "0701 建党日", "0707 抗战纪念日", "0801 建军节", "0910 教师节", "0918 ä¹Â·ä¸€å…«äº‹å˜çºªå¿µæ—¥", "1001*国庆节", "1031 万圣节", "1111 å…‰æ£èŠ‚", "1201 艾滋病日", "1213 å—äº¬å¤§å± æ€çºªå¿µæ—¥", "1224 平安夜", "1225 圣诞节"); //æŸæœˆçš„ç¬¬å‡ ä¸ªæ˜ŸæœŸå‡ ã€‚ 5,6,7,8 表示到数第 1,2,3,4 ä¸ªæ˜ŸæœŸå‡ var wFtv = new Array( //一月的最åŽä¸€ä¸ªæ˜ŸæœŸæ—¥ï¼ˆæœˆå€’数第一个星期日) "0520 æ¯äº²èŠ‚", "0630 父亲节", "1144 感æ©èŠ‚"); //农历节日 var lFtv = new Array( "0101*春节", "0115 元宵节", "0202 龙抬头", "0505 端åˆèŠ‚", "0707 七夕", "0715 ä¸å…ƒèŠ‚", "0815 ä¸ç§‹èŠ‚", "0909 é‡é˜³èŠ‚", "1208 腊八节", "1223 å°å¹´", "0100*除夕"); //====================================== 返回农历 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(date) { var objDate = new Date(date.getFullYear(), date.getMonth(), date.getDate()); var i, leap=0, temp=0 var baseDate = new Date(1900,0,31) // Macå’Œlinuxå¹³å°çš„firefox在æ¤å¤„会产生浮点数错误 var offset = Math.round((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 } /////////////////////////////////////////////////////////// // // lunar 2 solar // /////////////////////////////////////////////////////////// // year .month .day .isLeap .yearCyl .dayCyl .monCyl function Solar(date, isLeapMonth) { var lyear = date.getFullYear(), lmonth = date.getMonth() + 1, lday = date.getDate(), offset = 0, leap = isLeap(lyear); // increment year for(var i = 1900; i < lyear; i++) { offset += lYearDays(i); } // increment month // add days in all months up to the current month for (var i = 1; i < lmonth; i++) { // add extra days for leap month if (i == leapMonth(lyear)) { offset += leapDays(lyear); } offset += monthDays(lyear, i); } // if current month is leap month, add days in normal month if (leap && isLeapMonth) { offset += monthDays(lyear, i); } // increment offset += parseInt(lday) - 1; var baseDate = new Date(1900,0,31); var solarDate = new Date(baseDate.valueOf() + offset * 86400000); this.year = solarDate.getFullYear(); this.month = solarDate.getMonth(); this.day = solarDate.getDate(); this.isLeap = leap; } function isLeap(year) { return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); } function getAnimalYear(year) { return Animals[((year - 1900)%12)]; } //============================== ä¼ å…¥ offset 返回干支, 0=甲å function cyclical(num) { return(Gan[num%10]+Zhi[num%12]); } //======================================= è¿”å›žè¯¥å¹´çš„å¤æ´»èŠ‚(春分åŽç¬¬ä¸€æ¬¡æ»¡æœˆå‘¨åŽçš„第一主日) function easter(y) { var term2=sTerm(y,5); //å–得春分日期 var dayTerm2 = new Date(Date.UTC(y,2,term2,0,0,0,0)); //å–得春分的公历日期控件(春分一定出现在3月) var lDayTerm2 = new Lunar(dayTerm2); //å–å¾—å–得春分农历 if(lDayTerm2.day<15) //å–得下个月圆的相差天数 var lMlen= 15-lDayTerm2.day; else var lMlen= (lDayTerm2.isLeap? leapDays(y): monthDays(y,lDayTerm2.month)) - lDayTerm2.day + 15; //一天ç‰äºŽ 1000*60*60*24 = 86400000 毫秒 var l15 = new Date(dayTerm2.getTime() + 86400000*lMlen ); //æ±‚å‡ºç¬¬ä¸€æ¬¡æœˆåœ†ä¸ºå…¬åŽ†å‡ æ—¥ var dayEaster = new Date(l15.getTime() + 86400000*( 7-l15.getUTCDay() ) ); //求出下个周日 this.m = dayEaster.getUTCMonth(); this.d = dayEaster.getUTCDate(); } //====================== 䏿–‡æ—¥æœŸ function getCDay(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); } //////////////////////////////////////////////////////////////// // // 24 节气 // /////////////////////////////////////////////////////////////// var solarTerm = new Array("å°å¯’","大寒","立春","雨水","惊蛰","春分","清明", "谷雨","ç«‹å¤","å°æ»¡","芒ç§","å¤è‡³","å°æš‘","大暑","ç«‹ç§‹","处暑","白露","秋分", "寒露","霜é™","立冬","å°é›ª","大雪","冬至"); var solarTermBase = new Array(4,19,3,18,4,19,4,19,4,20,4,20,6,22,6,22,6,22,7,22,6,21,6,21); var solarTermIdx = '0123415341536789:;<9:=<>:=1>?012@015@015@015AB78CDE8CD=1FD01GH01GH01IH01IJ0KLMN;LMBEOPDQRST0RUH0RVH0RWH0RWM0XYMNZ[MB\\]PT^_ST`_WH`_WH`_WM`_WM`aYMbc[Mde]Sfe]gfh_gih_Wih_WjhaWjka[jkl[jmn]ope]qph_qrh_sth_W'; var solarTermOS = '211122112122112121222211221122122222212222222221222122222232222222222222222233223232223232222222322222112122112121222211222122222222222222222222322222112122112121222111211122122222212221222221221122122222222222222222222223222232222232222222222222112122112121122111211122122122212221222221221122122222222222222221211122112122212221222211222122222232222232222222222222112122112121111111222222112121112121111111222222111121112121111111211122112122112121122111222212111121111121111111111122112122112121122111211122112122212221222221222211111121111121111111222111111121111111111111111122112121112121111111222111111111111111111111111122111121112121111111221122122222212221222221222111011111111111111111111122111121111121111111211122112122112121122211221111011111101111111111111112111121111121111111211122112122112221222211221111011111101111111110111111111121111111111111111122112121112121122111111011111121111111111111111011111111112111111111111011111111111111111111221111011111101110111110111011011111111111111111221111011011101110111110111011011111101111111111211111001011101110111110110011011111101111111111211111001011001010111110110011011111101111111110211111001011001010111100110011011011101110111110211111001011001010011100110011001011101110111110211111001010001010011000100011001011001010111110111111001010001010011000111111111111111111111111100011001011001010111100111111001010001010000000111111000010000010000000100011001011001010011100110011001011001110111110100011001010001010011000110011001011001010111110111100000010000000000000000011001010001010011000111100000000000000000000000011001010001010000000111000000000000000000000000011001010000010000000'; // å½¢å¼å¦‚function sTerm(year, n),用æ¥è®¡ç®—æŸå¹´çš„第n个节气(从0å°å¯’ç®—èµ·ï¼‰ä¸ºå‡ å·ï¼Œè¿™ä¹ŸåŸºæœ¬è¢«è®¤å¯ä¸ºèŠ‚æ°”è®¡ç®—çš„åŸºæœ¬å½¢å¼ã€‚由于没个月份有两个节气,计算时需è¦è°ƒç”¨ä¸¤æ¬¡ï¼ˆnå’Œn+1) //===== æŸå¹´çš„第nä¸ªèŠ‚æ°”ä¸ºå‡ æ—¥ï¼ˆä»Ž0å°å¯’起算) function sTerm(y,n) { return(solarTermBase[n] + Math.floor( solarTermOS.charAt( ( Math.floor(solarTermIdx.charCodeAt(y-1900)) - 48) * 24 + n ) ) ); } ///////////////////////////////////////////////////////////////// // // calElement model // ///////////////////////////////////////////////////////////////// //============================== 阴历属性 function calElement(sYear,sMonth,sDay,week,lYear,lMonth,lDay,isLeap,cYear,cMonth,cDay) { //ç“£å¥ this.sYear = sYear; //公元年4使•°å— this.sMonth = sMonth; //å…¬å…ƒæœˆæ•°å— this.sDay = sDay; //å…¬å…ƒæ—¥æ•°å— this.week = week; //星期, 1ä¸ªä¸æ–‡ //农历 this.lYear = lYear; //公元年4使•°å— this.lMonth = lMonth; //å†œåŽ†æœˆæ•°å— this.lDay = lDay; //å†œåŽ†æ—¥æ•°å— this.isLeap = isLeap; //是å¦ä¸ºå†œåŽ†é—°æœˆ? //å…«å— this.cYear = cYear; //年柱, 2ä¸ªä¸æ–‡ this.cMonth = cMonth; //月柱, 2ä¸ªä¸æ–‡ this.cDay = cDay; //日柱, 2ä¸ªä¸æ–‡ this.lunarDay = getCDay(lDay); this.lunarMonth = cmonthName[lMonth - 1]; this.lunarYear = getAnimalYear(lYear); // this.color = ''; this.lunarFestival = ''; //农历节日 this.solarFestival = ''; //公历节日 this.solarTerms = ''; //节气 } /////////////////////////////////////////////////////////////// // // main // /////////////////////////////////////////////////////////////// // date's month should be --, example: 2012-5-21 -> new Date(2012, 4, 21) // no matter solar or lunar function CalendarConverter() { this.solar2lunar = function(date) { var sYear = date.getFullYear(), sMonth = date.getMonth(), sDay = date.getDate(), weekDay = nStr1[date.getDay()], lunar = new Lunar(date), lunarYear = lunar.year, lunarMonth = lunar.month, lunarDay = lunar.day, isLeap = lunar.isLeap; return addFstv(sYear, sMonth, sDay, weekDay, lunarYear, lunarMonth, lunarDay, isLeap); } this.lunar2solar = function(date, isLeapMonth) { var lunarYear = date.getFullYear(), lunarMonth = date.getMonth() + 1, lunarDay = date.getDate(), solar = new Solar(date, isLeapMonth), sYear = solar.year, sMonth = solar.month, sDay = solar.day, weekDay = nStr1[new Date(sYear, sMonth, sDay).getDay()], isLeap = solar.isLeap, cYear, cMonth, cDay, that = {}; return addFstv(sYear, sMonth, sDay, weekDay, lunarYear, lunarMonth, lunarDay, isLeap); } } function addFstv(sYear, sMonth, sDay, weekDay, lunarYear, lunarMonth, lunarDay, isLeap) { var cYear, cMonth, cDay, that = {}; ////////年柱 1900年立春åŽä¸ºåºšåå¹´(60进制36) if(sMonth < 2 ) { cYear=cyclical(sYear-1900+36-1); } else { cYear=cyclical(sYear-1900+36); } var term2=sTerm(sYear,2); //立春日期 ////////月柱 1900å¹´1月å°å¯’以å‰ä¸º ä¸™åæœˆ(60进制12) var firstNode = sTerm(sYear, sMonth*2) //返回当月「节ã€ä¸ºå‡ 日开始 cMonth = cyclical((sYear - 1900) * 12 + sMonth + 12); //ä¾èŠ‚æ°”è°ƒæ•´äºŒæœˆåˆ†çš„å¹´æŸ±, 以立春为界 if(sMonth == 1 && sDay >= term2) cYear = cyclical(sYear - 1900+36); //ä¾èŠ‚æ°”æœˆæŸ±, 以「节ã€ä¸ºç•Œ if(sDay >= firstNode) cMonth = cyclical((sYear - 1900) * 12 + sMonth + 13); //当月一日与 1900/1/1 相差天数 //1900/1/1与 1970/1/1 相差25567æ—¥, 1900/1/1 日柱为甲戌日(60进制10) var dayCyclical = Date.UTC(sYear, sMonth, 1, 0, 0, 0, 0)/86400000 + 25567 + 10; //日柱 cDay = cyclical(dayCyclical + sDay - 1); //sYear,sMonth,sDay,weekDay, //lYear,lMonth,lDay,isLeap, //cYear,cMonth,cDay that = new calElement(sYear, sMonth + 1, sDay, weekDay, lunarYear, lunarMonth, lunarDay, isLeap, cYear, cMonth, cDay); // 节气 tmp1=sTerm(sYear, sMonth * 2) - 1; tmp2=sTerm(sYear, sMonth * 2 + 1) - 1; if (tmp1 == (sDay - 1)) { that.solarTerms = solarTerm[sMonth * 2]; } if (tmp2 == (sDay - 1)) { that.solarTerms = solarTerm[sMonth * 2 + 1]; } //公历节日 for (var i = 0, item; item = sFtv[i]; i++) { if(item.match(/^(\d{2})(\d{2})([\s\*])(.+)$/)) { if(Number(RegExp.$1)==(sMonth+1)) { if (Number(RegExp.$2) == sDay) { that.solarFestival += RegExp.$4 + ' '; } } } } //月周节日 for (i = 0, item; item = wFtv[i]; i++) { if (item.match(/^(\d{2})(\d)(\d)([\s\*])(.+)$/)) { if (Number(RegExp.$1) == (sMonth + 1)) { tmp1 = Number(RegExp.$2); tmp2 = Number(RegExp.$3); if (tmp1 < 5) { var wFtvDate = (tmp2 == 0 ? 7 : 0) + (tmp1 - 1)*7 + tmp2; if (wFtvDate == sDay) { that.solarFestival += RegExp.$5 + ' '; break; } } } } } // 农历节日 for (i = 0, item; item = lFtv[i]; i++) { if (item.match(/^(\d{2})(.{2})([\s\*])(.+)$/)) { tmp1 = Number(RegExp.$1); tmp2 = Number(RegExp.$2); lMonLen = monthDays(lunarYear, lunarMonth); // 月份是12月,且为最åŽä¸€å¤©ï¼Œåˆ™è®¾ç½®ä¸ºæ˜¥èŠ‚ if ((tmp1 == lunarMonth && tmp2 == lunarDay) || (tmp2 == '00' && lunarMonth == 12 && lMonLen == lunarDay)) { that.lunarFestival += RegExp.$4 + ' '; break; } } } return that; } /* * example: * var cc =new CalendarConverter; * * cc.lunar2solar(new Date(2011, 0, 3)); ---> 2010,11,29 * cc.solar2lunar(new Date(2010, 10, 29)); ----> 2011, 1, 3 * * 农历转公历时,如果那一月是那一年的闰月,则需é¢å¤–ä¼ ä¸€ä¸ªå‚æ•°ï¼Œæ‰èƒ½å¾—到æ£ç¡®çš„公历日期 * cc.solar2lunar(new Date(2012, 4, 27)); ---> 2012å¹´4月åˆ7, å…¶ä¸ isLeap为true,表示为闰四月 * cc.lunar2solar(new Date(2012, 3, 7)) ---> 得到错误时间:2012, 4, 27 * cc.lunar2solar(new Date(2012, 3, 7), true) --> æ£ç¡®: 2012, 5, 27 * *result: * { * cDay: "戊戌" , cMonth: "䏿œª" , cYear: "壬辰" , isLeap: false // 该月是å¦ä¸ºé—°æœˆ , lDay: 18 , lMonth: 6 , lYear: 2012 , lunarDay: "åå…«" , lunarFestival: "" , lunarMonth: "å…" , lunarYear: "é¾™" , sDay: 5 , sMonth: 8 , sYear: 2012 , solarFestival: "" // 节日 , solarTerms: "" // 节气 , week: "æ—¥" // å‘¨å‡ } * */ window.CalendarConverter = CalendarConverter; if ('undefined' !== typeof module && module.exports) { module.exports = CalendarConverter; } else { root.CalendarConverter = CalendarConverter; } })()