123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496 |
- ;(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;
- }
- })()
|