Commit | Line | Data |
---|---|---|
dbda9b49 | 1 | /** |
90952d4e | 2 | * 農曆(陰曆)萬年曆 |
dbda9b49 | 3 | * LunarCalendar |
e39c4564 | 4 | * vervison : v0.1.4 |
dbda9b49 | 5 | * Github : https://github.com/zzyss86/LunarCalendar |
6 | * HomePage : http://www.tuijs.com/ | |
7 | * Author : JasonZhou | |
8 | * Email : zzyss86@qq.com | |
9 | */ | |
10 | ||
11 | (function(){ | |
12 | var extend = function(o, c){ | |
13 | if(o && c && typeof c == "object"){ | |
14 | for(var p in c){ | |
15 | o[p] = c[p]; | |
16 | } | |
17 | } | |
18 | return o; | |
19 | }; | |
90952d4e | 20 | |
dbda9b49 | 21 | var creatLenArr = function(year,month,len,start){ |
22 | var arr = []; | |
23 | start = start || 0; | |
24 | if(len<1)return arr; | |
25 | var k = start; | |
26 | for(var i=0;i<len;i++){ | |
27 | arr.push({year:year,month:month,day:k}); | |
28 | k++; | |
29 | } | |
30 | return arr; | |
31 | }; | |
90952d4e | 32 | |
33 | var errorCode = { //錯誤碼列表 | |
34 | 100 : '輸入的年份超過了可查詢範圍,僅支持1891至2100年', | |
35 | 101 : '參數輸入錯誤,請查閱文檔' | |
dbda9b49 | 36 | }; |
90952d4e | 37 | |
38 | var cache = null; //某年相同計算進行cache,以加速計算速度 | |
dbda9b49 | 39 | var cacheUtil = { //cache管理工具 |
40 | current : '', | |
41 | setCurrent : function(year){ | |
42 | if(this.current != year){ | |
43 | this.current = year; | |
44 | this.clear(); | |
45 | } | |
46 | }, | |
47 | set : function(key,value){ | |
48 | if(!cache) cache = {}; | |
49 | cache[key] = value; | |
50 | return cache[key]; | |
51 | }, | |
52 | get : function(key){ | |
53 | if(!cache) cache = {}; | |
54 | return cache[key]; | |
55 | }, | |
56 | clear : function(){ | |
57 | cache = null; | |
58 | } | |
59 | }; | |
90952d4e | 60 | |
dbda9b49 | 61 | var formateDayD4 = function(month,day){ |
62 | month = month+1; | |
63 | month = month<10 ? '0'+month : month; | |
64 | day = day<10 ? '0'+day : day; | |
65 | return 'd'+month+day; | |
66 | }; | |
90952d4e | 67 | |
dbda9b49 | 68 | var minYear = 1890;//最小年限 |
69 | var maxYear = 2100;//最大年限 | |
70 | var DATA = { | |
71 | heavenlyStems: ['甲', '乙', '丙', '丁', '戊', '己', '庚', '辛', '壬', '癸'], //天干 | |
72 | earthlyBranches: ['子', '丑', '寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌', '亥'], //地支 | |
90952d4e | 73 | zodiac: ['鼠','牛','虎','兔','龍','蛇','馬','羊','猴','雞','狗','豬'], //對應地支十二生肖 |
74 | solarTerm: ['小寒', '大寒', '立春', '雨水', '驚蟄', '春分', '清明', '穀雨', '立夏', '小滿', '芒種', '夏至', '小暑', '大暑', '立秋', '處暑', '白露', '秋分', '寒露', '霜降', '立冬', '小雪', '大雪','冬至'], //二十四節氣 | |
dbda9b49 | 75 | monthCn: ['正', '二', '三', '四', '五', '六', '七', '八', '九', '十', '十一', '十二'], |
76 | dateCn: ['初一', '初二', '初三', '初四', '初五', '初六', '初七', '初八', '初九', '初十', '十一', '十二', '十三', '十四', '十五', '十六', '十七', '十八', '十九', '二十', '廿一', '廿二', '廿三', '廿四', '廿五', '廿六', '廿七', '廿八', '廿九', '三十', '卅一'] | |
77 | }; | |
90952d4e | 78 | |
79 | //中國節日放假安排,外部設置,0無特殊安排,1工作,2放假 | |
dbda9b49 | 80 | var worktime = {}; |
90952d4e | 81 | //默認設置2013-2014年放假安排 |
82 | worktime.y2013 = {"d0101":2,"d0102":2,"d0103":2,"d0105":1,"d0106":1,"d0209":2,"d0210":2,"d0211" :2,"d0212":2,"d0213":2,"d0214":2,"d0215":2,"d0216":1,"d0217":1,"d0404":2,"d0405":2 ,"d0406":2,"d0407":1,"d0427":1,"d0428":1,"d0429":2,"d0430":2,"d0501":2,"d0608":1," d0609":1,"d0610":2,"d0611":2,"d0612":2,"d0919":2,"d0920":2,"d0921":2,"d0922":1,"d0929" :1,"d1001":2,"d1002":2,"d1003":2,"d1004":2,"d1005":2,"d1006":2,"d1007":2,"d1012":1 }; | |
83 | worktime.y2014 = {"d0101":2,"d0126":1,"d0131":2,"d0201":2,"d0202":2,"d0203":2,"d0204":2,"d0205" :2,"d0206":2,"d0208":1,"d0405":2,"d0407":2,"d0501":2,"d0502":2,"d0503":2,"d0504":1 ,"d0602":2,"d0908":2,"d0928":1,"d1001":2,"d1002":2,"d1003":2,"d1004":2,"d1005":2," d1006":2,"d1007":2,"d1011":1}; | |
84 | ||
85 | //公曆節日 | |
dbda9b49 | 86 | var solarFestival = { |
90952d4e | 87 | 'd0101':'元旦節', |
88 | 'd0202':'世界濕地日', | |
89 | 'd0210':'國際氣象節', | |
90 | 'd0214':'情人節', | |
91 | 'd0301':'國際海豹日', | |
92 | 'd0303':'全國愛耳日', | |
93 | 'd0305':'學雷鋒紀念日', | |
94 | 'd0308':'婦女節', | |
95 | 'd0312':'植樹節孫中山逝世紀念日', | |
96 | 'd0314':'國際警察日', | |
97 | 'd0315':'消費者權益日', | |
98 | 'd0317':'中國國醫節國際航海日', | |
99 | 'd0321':'世界森林日消除種族歧視國際日世界兒歌日', | |
dbda9b49 | 100 | 'd0322':'世界水日', |
90952d4e | 101 | 'd0323':'世界氣象日', |
102 | 'd0324':'世界防治結核病日', | |
103 | 'd0325':'全國中小學生安全教育日', | |
104 | 'd0330':'巴勒斯坦國土日', | |
105 | 'd0401':'愚人節全國愛國衛生運動月(四月) 稅收宣傳月(四月)', | |
106 | 'd0407':'世界衛生日', | |
dbda9b49 | 107 | 'd0422':'世界地球日', |
90952d4e | 108 | 'd0423':'世界圖書和版權日', |
109 | 'd0424':'亞非新聞工作者日', | |
110 | 'd0501':'勞動節', | |
111 | 'd0504':'青年節', | |
dbda9b49 | 112 | 'd0505':'碘缺乏病防治日', |
90952d4e | 113 | 'd0508':'世界紅十字日', |
114 | 'd0512':'國際護士節', | |
115 | 'd0515':'國際家庭日', | |
116 | 'd0517':'世界電信日', | |
117 | 'd0518':'國際博物館日', | |
118 | 'd0520':'全國學生營養日', | |
119 | 'd0522':'國際生物多樣性日', | |
120 | 'd0523':'國際牛奶日', | |
121 | 'd0531':'世界無菸日', | |
122 | 'd0601':'國際兒童節', | |
123 | 'd0605':'世界環境日', | |
124 | 'd0606':'全國愛眼日', | |
125 | 'd0617':'防治荒漠化和乾旱日', | |
126 | 'd0623':'國際奧林匹剋日', | |
127 | 'd0625':'全國土地日', | |
128 | 'd0626':'國際禁毒日', | |
129 | 'd0701':'香港回歸紀念日中共誕辰世界建築日', | |
130 | 'd0702':'國際體育記者日', | |
131 | 'd0707':'抗日戰爭紀念日', | |
dbda9b49 | 132 | 'd0711':'世界人口日', |
90952d4e | 133 | 'd0730':'非洲婦女日', |
134 | 'd0801':'建軍節', | |
135 | 'd0808':'中國男子節(爸爸節)', | |
136 | 'd0815':'抗日戰爭勝利紀念', | |
137 | 'd0908':'國際掃盲日國際新聞工作者日', | |
138 | 'd0909':'毛澤東逝世紀念', | |
139 | 'd0910':'中國教師節', | |
140 | 'd0914':'世界清潔地球日', | |
141 | 'd0916':'國際臭氧層保護日', | |
142 | 'd0918':'九一八事變紀念日', | |
143 | 'd0920':'國際愛牙日', | |
144 | 'd0927':'世界旅遊日', | |
145 | 'd0928':'孔子誕辰', | |
146 | 'd1001':'國慶節世界音樂日國際老人節', | |
147 | 'd1002':'國際和平與民主自由鬥爭日', | |
148 | 'd1004':'世界動物日', | |
149 | 'd1006':'老人節', | |
150 | 'd1008':'全國高血壓日世界視覺日', | |
151 | 'd1009':'世界郵政日萬國郵聯日', | |
152 | 'd1010':'辛亥革命紀念日世界精神衛生日', | |
153 | 'd1013':'世界保健日國際教師節', | |
154 | 'd1014':'世界標準日', | |
155 | 'd1015':'國際盲人節(白手杖節)', | |
156 | 'd1016':'世界糧食日', | |
157 | 'd1017':'世界消除貧困日', | |
158 | 'd1022':'世界傳統醫藥日', | |
159 | 'd1024':'聯合國日世界發展信息日', | |
160 | 'd1031':'世界勤儉日', | |
161 | 'd1107':'十月社會主義革命紀念日', | |
162 | 'd1108':'中國記者日', | |
163 | 'd1109':'全國消防安全宣傳教育日', | |
164 | 'd1110':'世界青年節', | |
165 | 'd1111':'國際科學與和平周(本日所屬的一週)', | |
166 | 'd1112':'孫中山誕辰紀念日', | |
dbda9b49 | 167 | 'd1114':'世界糖尿病日', |
90952d4e | 168 | 'd1117':'國際大學生節世界學生節', |
169 | 'd1121':'世界問候日世界電視日', | |
170 | 'd1129':'國際聲援巴勒斯坦人民國際日', | |
dbda9b49 | 171 | 'd1201':'世界艾滋病日', |
90952d4e | 172 | 'd1203':'世界殘疾人日', |
173 | 'd1205':'國際經濟和社會發展志願人員日', | |
174 | 'd1208':'國際兒童電視日', | |
dbda9b49 | 175 | 'd1209':'世界足球日', |
90952d4e | 176 | 'd1210':'世界人權日', |
177 | 'd1212':'西安事變紀念日', | |
178 | 'd1213':'南京大屠殺(1937年)紀念日!緊記血淚史!', | |
179 | 'd1220':'澳門回歸紀念', | |
180 | 'd1221':'國際籃球日', | |
dbda9b49 | 181 | 'd1224':'平安夜', |
90952d4e | 182 | 'd1225':'聖誕節', |
183 | 'd1226':'毛澤東誕辰紀念' | |
dbda9b49 | 184 | }; |
90952d4e | 185 | |
186 | //農曆節日 | |
dbda9b49 | 187 | var lunarFestival = { |
90952d4e | 188 | 'd0101':'春節', |
189 | 'd0115':'元宵節', | |
190 | 'd0202':'龍抬頭節', | |
191 | 'd0323':'媽祖生辰', | |
192 | 'd0505':'端午節', | |
193 | 'd0707':'七夕情人節', | |
194 | 'd0715':'中元節', | |
195 | 'd0815':'中秋節', | |
196 | 'd0909':'重陽節', | |
197 | 'd1015':'下元節', | |
198 | 'd1208':'臘八節', | |
dbda9b49 | 199 | 'd1223':'小年', |
200 | 'd0100':'除夕' | |
201 | } | |
202 | ||
203 | /** | |
90952d4e | 204 | * 1890 - 2100 年的農曆數據 |
205 | * 數據格式:[0,2,9,21936] | |
206 | * [閏月所在月,0為沒有閏月; *正月初一對應公曆月; *正月初一對應公曆日; *農曆每月的天數的數組(需轉換為二進制,得到每月大小,0=小月(29日),1=大月(30日));] | |
dbda9b49 | 207 | */ |
208 | var lunarInfo = [[2,1,21,22184],[0,2,9,21936],[6,1,30,9656],[0,2,17,9584],[0,2,6,21168],[5,1,26,43344],[0,2,13,59728],[0,2,2,27296],[3,1,22,44368],[0,2,10,43856],[8,1,30,19304],[0,2,19,19168],[0,2,8,42352],[5,1,29,21096],[0,2,16,53856],[0,2,4,55632],[4,1,25,27304],[0,2,13,22176],[0,2,2,39632],[2,1,22,19176],[0,2,10,19168],[6,1,30,42200],[0,2,18,42192],[0,2,6,53840],[5,1,26,54568],[0,2,14,46400],[0,2,3,54944],[2,1,23,38608],[0,2,11,38320],[7,2,1,18872],[0,2,20,18800],[0,2,8,42160],[5,1,28,45656],[0,2,16,27216],[0,2,5,27968],[4,1,24,44456],[0,2,13,11104],[0,2,2,38256],[2,1,23,18808],[0,2,10,18800],[6,1,30,25776],[0,2,17,54432],[0,2,6,59984],[5,1,26,27976],[0,2,14,23248],[0,2,4,11104],[3,1,24,37744],[0,2,11,37600],[7,1,31,51560],[0,2,19,51536],[0,2,8,54432],[6,1,27,55888],[0,2,15,46416],[0,2,5,22176],[4,1,25,43736],[0,2,13,9680],[0,2,2,37584],[2,1,22,51544],[0,2,10,43344],[7,1,29,46248],[0,2,17,27808],[0,2,6,46416],[5,1,27,21928],[0,2,14,19872],[0,2,3,42416],[3,1,24,21176],[0,2,12,21168],[8,1,31,43344],[0,2,18,59728],[0,2,8,27296],[6,1,28,44368],[0,2,15,43856],[0,2,5,19296],[4,1,25,42352],[0,2,13,42352],[0,2,2,21088],[3,1,21,59696],[0,2,9,55632],[7,1,30,23208],[0,2,17,22176],[0,2,6,38608],[5,1,27,19176],[0,2,15,19152],[0,2,3,42192],[4,1,23,53864],[0,2,11,53840],[8,1,31,54568],[0,2,18,46400],[0,2,7,46752],[6,1,28,38608],[0,2,16,38320],[0,2,5,18864],[4,1,25,42168],[0,2,13,42160],[10,2,2,45656],[0,2,20,27216],[0,2,9,27968],[6,1,29,44448],[0,2,17,43872],[0,2,6,38256],[5,1,27,18808],[0,2,15,18800],[0,2,4,25776],[3,1,23,27216],[0,2,10,59984],[8,1,31,27432],[0,2,19,23232],[0,2,7,43872],[5,1,28,37736],[0,2,16,37600],[0,2,5,51552],[4,1,24,54440],[0,2,12,54432],[0,2,1,55888],[2,1,22,23208],[0,2,9,22176],[7,1,29,43736],[0,2,18,9680],[0,2,7,37584],[5,1,26,51544],[0,2,14,43344],[0,2,3,46240],[4,1,23,46416],[0,2,10,44368],[9,1,31,21928],[0,2,19,19360],[0,2,8,42416],[6,1,28,21176],[0,2,16,21168],[0,2,5,43312],[4,1,25,29864],[0,2,12,27296],[0,2,1,44368],[2,1,22,19880],[0,2,10,19296],[6,1,29,42352],[0,2,17,42208],[0,2,6,53856],[5,1,26,59696],[0,2,13,54576],[0,2,3,23200],[3,1,23,27472],[0,2,11,38608],[11,1,31,19176],[0,2,19,19152],[0,2,8,42192],[6,1,28,53848],[0,2,15,53840],[0,2,4,54560],[5,1,24,55968],[0,2,12,46496],[0,2,1,22224],[2,1,22,19160],[0,2,10,18864],[7,1,30,42168],[0,2,17,42160],[0,2,6,43600],[5,1,26,46376],[0,2,14,27936],[0,2,2,44448],[3,1,23,21936],[0,2,11,37744],[8,2,1,18808],[0,2,19,18800],[0,2,8,25776],[6,1,28,27216],[0,2,15,59984],[0,2,4,27424],[4,1,24,43872],[0,2,12,43744],[0,2,2,37600],[3,1,21,51568],[0,2,9,51552],[7,1,29,54440],[0,2,17,54432],[0,2,5,55888],[5,1,26,23208],[0,2,14,22176],[0,2,3,42704],[4,1,23,21224],[0,2,11,21200],[8,1,31,43352],[0,2,19,43344],[0,2,7,46240],[6,1,27,46416],[0,2,15,44368],[0,2,5,21920],[4,1,24,42448],[0,2,12,42416],[0,2,2,21168],[3,1,22,43320],[0,2,9,26928],[7,1,29,29336],[0,2,17,27296],[0,2,6,44368],[5,1,26,19880],[0,2,14,19296],[0,2,3,42352],[4,1,24,21104],[0,2,10,53856],[8,1,30,59696],[0,2,18,54560],[0,2,7,55968],[6,1,27,27472],[0,2,15,22224],[0,2,5,19168],[4,1,25,42216],[0,2,12,42192],[0,2,1,53584],[2,1,21,55592],[0,2,9,54560]]; | |
90952d4e | 209 | |
dbda9b49 | 210 | /** |
90952d4e | 211 | * 二十四節氣數據,節氣點時間(單位是分鐘) |
212 | * 從0小寒起算 | |
dbda9b49 | 213 | */ |
90952d4e | 214 | var termInfo = [0,21208,42467,63836,85337,107014,128867,150921,173149,195551,218072,240693,263343,285989,308563,331033,353350,375494,397447,419210,440795,462224,483532, 504758]; |
215 | ||
dbda9b49 | 216 | /** |
90952d4e | 217 | * 判斷農曆年閏月數 |
218 | * @param {Number} year 農曆年 | |
219 | * return 閏月數(月份從1開始) | |
dbda9b49 | 220 | */ |
221 | function getLunarLeapYear(year){ | |
222 | var yearData = lunarInfo[year-minYear]; | |
223 | return yearData[0]; | |
224 | }; | |
90952d4e | 225 | |
dbda9b49 | 226 | /** |
90952d4e | 227 | * 獲取農曆年份一年的每月的天數及一年的總天數 |
228 | * @param {Number} year 農曆年 | |
dbda9b49 | 229 | */ |
230 | function getLunarYearDays(year){ | |
231 | var yearData = lunarInfo[year-minYear]; | |
90952d4e | 232 | var leapMonth = yearData[0]; //閏月 |
dbda9b49 | 233 | var monthData = yearData[3].toString(2); |
234 | var monthDataArr = monthData.split(''); | |
90952d4e | 235 | |
236 | //還原數據至16位,少於16位的在前面插入0(二進制存儲時前面的0被忽略) | |
dbda9b49 | 237 | for(var i=0;i<16-monthDataArr.length;i++){ |
238 | monthDataArr.unshift(0); | |
239 | } | |
90952d4e | 240 | |
241 | var len = leapMonth ? 13 : 12; //該年有幾個月 | |
dbda9b49 | 242 | var yearDays = 0; |
243 | var monthDays = []; | |
244 | for(var i=0;i<len;i++){ | |
245 | if(monthDataArr[i]==0){ | |
246 | yearDays += 29; | |
247 | monthDays.push(29); | |
248 | }else{ | |
249 | yearDays += 30; | |
250 | monthDays.push(30); | |
251 | } | |
252 | } | |
90952d4e | 253 | |
dbda9b49 | 254 | return { |
255 | yearDays : yearDays, | |
256 | monthDays : monthDays | |
257 | }; | |
258 | }; | |
90952d4e | 259 | |
dbda9b49 | 260 | /** |
90952d4e | 261 | * 通過間隔天數查找農曆日期 |
262 | * @param {Number} year,between 農曆年,間隔天數 | |
dbda9b49 | 263 | */ |
264 | function getLunarDateByBetween(year,between){ | |
265 | var lunarYearDays = getLunarYearDays(year); | |
266 | var end = between>0 ? between : lunarYearDays.yearDays - Math.abs(between); | |
267 | var monthDays = lunarYearDays.monthDays; | |
268 | var tempDays = 0; | |
269 | var month = 0; | |
270 | for(var i=0;i<monthDays.length;i++){ | |
271 | tempDays += monthDays[i]; | |
272 | if(tempDays > end){ | |
273 | month = i; | |
274 | tempDays = tempDays-monthDays[i]; | |
275 | break; | |
276 | } | |
277 | } | |
90952d4e | 278 | |
dbda9b49 | 279 | return [year,month,end - tempDays + 1]; |
280 | }; | |
281 | ||
282 | /** | |
90952d4e | 283 | * 根據距離正月初一的天數計算農曆日期 |
284 | * @param {Number} year 公曆年,月,日 | |
dbda9b49 | 285 | */ |
286 | function getLunarByBetween(year,month,day){ | |
287 | var yearData = lunarInfo[year-minYear]; | |
288 | var zenMonth = yearData[1]; | |
289 | var zenDay = yearData[2]; | |
90952d4e | 290 | var between = getDaysBetweenSolar(year, zenMonth-1, zenDay, year, month, day); |
dbda9b49 | 291 | if(between==0){ //正月初一 |
292 | return [year,0,1]; | |
293 | }else{ | |
294 | var lunarYear = between>0 ? year : year-1; | |
295 | return getLunarDateByBetween(lunarYear,between); | |
296 | } | |
297 | }; | |
90952d4e | 298 | |
dbda9b49 | 299 | /** |
90952d4e | 300 | * 兩個公曆日期之間的天數 |
dbda9b49 | 301 | */ |
90952d4e | 302 | function getDaysBetweenSolar(year, month, day, year1, month1, day1){ |
dbda9b49 | 303 | var date = new Date(year,month,day).getTime(); |
304 | var date1 = new Date(year1,month1,day1).getTime(); | |
305 | return (date1-date) / 86400000; | |
306 | }; | |
90952d4e | 307 | |
dbda9b49 | 308 | /** |
90952d4e | 309 | * 計算農曆日期離正月初一有多少天 |
310 | * @param {Number} year,month,day 農年,月(0-12,有閏月),日 | |
dbda9b49 | 311 | */ |
312 | function getDaysBetweenZheng(year,month,day){ | |
313 | var lunarYearDays = getLunarYearDays(year); | |
314 | var monthDays = lunarYearDays.monthDays; | |
315 | var days = 0; | |
316 | for(var i=0;i<monthDays.length;i++){ | |
317 | if(i<month){ | |
318 | days += monthDays[i]; | |
319 | }else{ | |
320 | break; | |
321 | } | |
322 | }; | |
323 | return days+day-1; | |
324 | }; | |
90952d4e | 325 | |
dbda9b49 | 326 | /** |
90952d4e | 327 | * 某年的第n個節氣為幾日 |
328 | * 31556925974.7為地球公轉週期,是毫秒 | |
329 | * 1890年的正小寒點:01-05 16:02:31,1890年為基準點 | |
330 | * @param {Number} y 公曆年 | |
331 | * @param {Number} n 第幾個節氣,從0小寒起算 | |
332 | * 由於農曆24節氣交節時刻採用近似算法,可能存在少量誤差(30分鐘內) | |
dbda9b49 | 333 | */ |
334 | function getTerm(y,n) { | |
90952d4e | 335 | var offDate = new Date( ( 31556925974.7*(y-1890) + termInfo[n]*60000 ) + Date.UTC(1890,0,5,16,2,31) ); |
dbda9b49 | 336 | return(offDate.getUTCDate()); |
337 | }; | |
90952d4e | 338 | |
dbda9b49 | 339 | /** |
90952d4e | 340 | * 獲取公曆年一年的二十四節氣 |
341 | * 返回key:日期,value:節氣中文名 | |
dbda9b49 | 342 | */ |
343 | function getYearTerm(year){ | |
344 | var res = {}; | |
345 | var month = 0; | |
346 | for(var i=0;i<24;i++){ | |
347 | var day = getTerm(year,i); | |
348 | if(i%2==0)month++ | |
349 | res[formateDayD4(month-1,day)] = DATA.solarTerm[i]; | |
350 | } | |
351 | return res; | |
352 | }; | |
90952d4e | 353 | |
dbda9b49 | 354 | /** |
90952d4e | 355 | * 獲取生肖 |
356 | * @param {Number} year 干支所在年(默認以立春前的公曆年作為基數) | |
dbda9b49 | 357 | */ |
358 | function getYearZodiac(year){ | |
90952d4e | 359 | var num = year-1890+25; //參考干支紀年的計算,生肖對應地支 |
dbda9b49 | 360 | return DATA.zodiac[num%12]; |
361 | }; | |
90952d4e | 362 | |
dbda9b49 | 363 | /** |
90952d4e | 364 | * 計算天干地支 |
365 | * @param {Number} num 60進制中的位置(把60個天干地支,當成一個60進制的數) | |
dbda9b49 | 366 | */ |
367 | function cyclical(num) { | |
368 | return(DATA.heavenlyStems[num%10]+DATA.earthlyBranches[num%12]); | |
369 | } | |
90952d4e | 370 | |
dbda9b49 | 371 | /** |
90952d4e | 372 | * 獲取乾支紀年 |
dbda9b49 | 373 | * @param {Number} year 干支所在年 |
90952d4e | 374 | * @param {Number} offset 偏移量,默認為0,便於查詢一個年跨兩個乾支紀年(以立春為分界線) |
dbda9b49 | 375 | */ |
376 | function getLunarYearName(year,offset){ | |
377 | offset = offset || 0; | |
90952d4e | 378 | //1890年1月小寒(小寒一般是1月5或6日)以前為己丑年,在60進制中排25 |
dbda9b49 | 379 | return cyclical(year-1890+25+offset); |
380 | }; | |
90952d4e | 381 | |
dbda9b49 | 382 | /** |
90952d4e | 383 | * 獲取乾支紀月 |
384 | * @param {Number} year,month 公曆年,干支所在月 | |
385 | * @param {Number} offset 偏移量,默認為0,便於查詢一個月跨兩個乾支紀月(有立春的2月) | |
dbda9b49 | 386 | */ |
387 | function getLunarMonthName(year,month,offset){ | |
388 | offset = offset || 0; | |
90952d4e | 389 | //1890年1月小寒以前為丙子月,在60進制中排12 |
dbda9b49 | 390 | return cyclical((year-1890)*12+month+12+offset); |
391 | }; | |
90952d4e | 392 | |
dbda9b49 | 393 | /** |
90952d4e | 394 | * 獲取乾支紀日 |
395 | * @param {Number} year,month,day 公曆年,月,日 | |
dbda9b49 | 396 | */ |
397 | function getLunarDayName(year,month,day){ | |
90952d4e | 398 | //當日與1890/1/1 相差天數 |
399 | //1890/1/1與1970/1/1 相差29219日, 1890/1/1 日柱為壬午日(60進制18) | |
dbda9b49 | 400 | var dayCyclical = Date.UTC(year,month,day)/86400000+29219+18; |
401 | return cyclical(dayCyclical); | |
402 | }; | |
90952d4e | 403 | |
dbda9b49 | 404 | /** |
90952d4e | 405 | * 獲取公曆月份的天數 |
406 | * @param {Number} year 公曆年 | |
407 | * @param {Number} month 公曆月 | |
dbda9b49 | 408 | */ |
409 | function getSolarMonthDays(year,month){ | |
410 | var monthDays = [31,isLeapYear(year)?29:28,31,30,31,30,31,31,30,31,30,31]; | |
411 | return monthDays[month]; | |
412 | }; | |
90952d4e | 413 | |
dbda9b49 | 414 | /** |
90952d4e | 415 | * 判斷公曆年是否是閏年 |
416 | * @param {Number} year 公曆年 | |
dbda9b49 | 417 | */ |
418 | function isLeapYear(year){ | |
419 | return ((year%4==0 && year%100 !=0) || (year%400==0)); | |
420 | }; | |
90952d4e | 421 | |
dbda9b49 | 422 | /* |
90952d4e | 423 | * 統一日期輸入參數(輸入月份從1開始,內部月份統一從0開始) |
dbda9b49 | 424 | */ |
425 | function formateDate(year,month,day,_minYear){ | |
426 | var argsLen = arguments.length; | |
427 | var now = new Date(); | |
428 | year = argsLen ? parseInt(year,10) : now.getFullYear(); | |
429 | month = argsLen ? parseInt(month-1,10) : now.getMonth(); | |
430 | day = argsLen ? parseInt(day,10) || now.getDate() : now.getDate(); | |
431 | if(year < (_minYear ? _minYear : minYear+1) || year > maxYear)return {error:100, msg:errorCode[100]}; | |
432 | return { | |
433 | year : year, | |
434 | month : month, | |
435 | day : day | |
436 | }; | |
437 | }; | |
90952d4e | 438 | |
dbda9b49 | 439 | /** |
90952d4e | 440 | * 將農曆轉換為公曆 |
441 | * @param {Number} year,month,day 農曆年,月(1-13,有閏月),日 | |
dbda9b49 | 442 | */ |
443 | function lunarToSolar(_year,_month,_day){ | |
444 | var inputDate = formateDate(_year,_month,_day); | |
445 | if(inputDate.error)return inputDate; | |
446 | var year = inputDate.year; | |
447 | var month = inputDate.month; | |
448 | var day = inputDate.day; | |
90952d4e | 449 | |
450 | var between = getDaysBetweenZheng(year,month,day); //離正月初一的天數 | |
dbda9b49 | 451 | var yearData = lunarInfo[year-minYear]; |
452 | var zenMonth = yearData[1]; | |
453 | var zenDay = yearData[2]; | |
90952d4e | 454 | |
dbda9b49 | 455 | var offDate = new Date(year,zenMonth-1,zenDay).getTime() + between * 86400000; |
456 | offDate = new Date(offDate); | |
457 | return { | |
458 | year : offDate.getFullYear(), | |
459 | month : offDate.getMonth()+1, | |
460 | day : offDate.getDate() | |
461 | }; | |
462 | }; | |
90952d4e | 463 | |
dbda9b49 | 464 | /** |
90952d4e | 465 | * 將公曆轉換為農曆 |
466 | * @param {Number} year,month,day 公曆年,月,日 | |
dbda9b49 | 467 | */ |
468 | function solarToLunar(_year,_month,_day){ | |
469 | var inputDate = formateDate(_year,_month,_day,minYear); | |
470 | if(inputDate.error)return inputDate; | |
471 | var year = inputDate.year; | |
472 | var month = inputDate.month; | |
473 | var day = inputDate.day; | |
90952d4e | 474 | |
dbda9b49 | 475 | cacheUtil.setCurrent(year); |
476 | //立春日期 | |
477 | var term2 = cacheUtil.get('term2') ? cacheUtil.get('term2') : cacheUtil.set('term2',getTerm(year,2)); | |
90952d4e | 478 | //二十四節氣 |
dbda9b49 | 479 | var termList = cacheUtil.get('termList') ? cacheUtil.get('termList') : cacheUtil.set('termList',getYearTerm(year)); |
90952d4e | 480 | |
481 | var firstTerm = getTerm(year,month*2); //某月第一個節氣開始日期 | |
dbda9b49 | 482 | var GanZhiYear = (month>1 || month==1 && day>=term2) ? year+1 : year;//干支所在年份 |
90952d4e | 483 | var GanZhiMonth = day>=firstTerm ? month+1 : month; //干支所在月份(以節氣為界) |
484 | ||
dbda9b49 | 485 | var lunarDate = getLunarByBetween(year,month,day); |
486 | var lunarLeapMonth = getLunarLeapYear(lunarDate[0]); | |
487 | var lunarMonthName = ''; | |
488 | if(lunarLeapMonth>0 && lunarLeapMonth==lunarDate[1]){ | |
90952d4e | 489 | lunarMonthName = '閏'+DATA.monthCn[lunarDate[1]-1]+'月'; |
dbda9b49 | 490 | }else if(lunarLeapMonth>0 && lunarDate[1]>lunarLeapMonth){ |
491 | lunarMonthName = DATA.monthCn[lunarDate[1]-1]+'月'; | |
492 | }else{ | |
493 | lunarMonthName = DATA.monthCn[lunarDate[1]]+'月'; | |
494 | } | |
90952d4e | 495 | |
496 | //農曆節日判斷 | |
dbda9b49 | 497 | var lunarFtv = ''; |
498 | var lunarMonthDays = getLunarYearDays(lunarDate[0]).monthDays; | |
499 | //除夕 | |
500 | if(lunarDate[1] == lunarMonthDays.length-1 && lunarDate[2]==lunarMonthDays[lunarMonthDays.length-1]){ | |
501 | lunarFtv = lunarFestival['d0100']; | |
502 | }else if(lunarLeapMonth>0 && lunarDate[1]>lunarLeapMonth){ | |
503 | lunarFtv = lunarFestival[formateDayD4(lunarDate[1]-1,lunarDate[2])]; | |
504 | }else{ | |
505 | lunarFtv = lunarFestival[formateDayD4(lunarDate[1],lunarDate[2])]; | |
506 | } | |
90952d4e | 507 | |
dbda9b49 | 508 | var res = { |
509 | zodiac : getYearZodiac(GanZhiYear), | |
510 | GanZhiYear : getLunarYearName(GanZhiYear), | |
511 | GanZhiMonth : getLunarMonthName(year,GanZhiMonth), | |
512 | GanZhiDay : getLunarDayName(year,month,day), | |
90952d4e | 513 | //放假安排:0無特殊安排,1工作,2放假 |
dbda9b49 | 514 | worktime : worktime['y'+year] && worktime['y'+year][formateDayD4(month,day)] ? worktime['y'+year][formateDayD4(month,day)] : 0, |
515 | term : termList[formateDayD4(month,day)], | |
90952d4e | 516 | |
dbda9b49 | 517 | lunarYear : lunarDate[0], |
518 | lunarMonth : lunarDate[1]+1, | |
519 | lunarDay : lunarDate[2], | |
520 | lunarMonthName : lunarMonthName, | |
521 | lunarDayName : DATA.dateCn[lunarDate[2]-1], | |
522 | lunarLeapMonth : lunarLeapMonth, | |
90952d4e | 523 | |
dbda9b49 | 524 | solarFestival : solarFestival[formateDayD4(month,day)], |
525 | lunarFestival : lunarFtv | |
526 | }; | |
527 | ||
528 | return res; | |
529 | }; | |
90952d4e | 530 | |
dbda9b49 | 531 | /** |
90952d4e | 532 | * 獲取指定公曆月份的農曆數據 |
dbda9b49 | 533 | * return res{Object} |
90952d4e | 534 | * @param {Number} year,month 公曆年,月 |
535 | * @param {Boolean} fill 是否用上下月數據補齊首尾空缺,首例數據從週日開始 | |
dbda9b49 | 536 | */ |
537 | function calendar(_year,_month,fill){ | |
538 | var inputDate = formateDate(_year,_month); | |
539 | if(inputDate.error)return inputDate; | |
540 | var year = inputDate.year; | |
541 | var month = inputDate.month; | |
90952d4e | 542 | |
dbda9b49 | 543 | var calendarData = solarCalendar(year,month+1,fill); |
544 | for(var i=0;i<calendarData.monthData.length;i++){ | |
545 | var cData = calendarData.monthData[i]; | |
546 | var lunarData = solarToLunar(cData.year,cData.month,cData.day); | |
547 | extend(calendarData.monthData[i],lunarData); | |
548 | } | |
549 | return calendarData; | |
550 | }; | |
90952d4e | 551 | |
dbda9b49 | 552 | /** |
90952d4e | 553 | * 公曆某月日曆 |
dbda9b49 | 554 | * return res{Object} |
90952d4e | 555 | * @param {Number} year,month 公曆年,月 |
556 | * @param {Boolean} fill 是否用上下月數據補齊首尾空缺,首例數據從週日開始(7*6陣列) | |
dbda9b49 | 557 | */ |
558 | function solarCalendar(_year,_month,fill){ | |
559 | var inputDate = formateDate(_year,_month); | |
560 | if(inputDate.error)return inputDate; | |
561 | var year = inputDate.year; | |
562 | var month = inputDate.month; | |
90952d4e | 563 | |
740058ad | 564 | var firstDate = new Date(year,month,1); |
dbda9b49 | 565 | var preMonthDays,preMonthData,nextMonthData; |
90952d4e | 566 | |
dbda9b49 | 567 | var res = { |
90952d4e | 568 | firstDay : firstDate.getDay(), //該月1號星期幾 |
569 | monthDays : getSolarMonthDays(year,month), //該月天數 | |
dbda9b49 | 570 | monthData : [] |
571 | }; | |
90952d4e | 572 | |
dbda9b49 | 573 | res.monthData = creatLenArr(year,month+1,res.monthDays,1); |
574 | ||
575 | if(fill){ | |
90952d4e | 576 | if(res.firstDay > 0){ //前補 |
dbda9b49 | 577 | var preYear = month-1<0 ? year-1 : year; |
578 | var preMonth = month-1<0 ? 11 : month-1; | |
579 | preMonthDays = getSolarMonthDays(preYear,preMonth); | |
740058ad | 580 | preMonthData = creatLenArr(preYear,preMonth+1,res.firstDay,preMonthDays-res.firstDay+1); |
dbda9b49 | 581 | res.monthData = preMonthData.concat(res.monthData); |
582 | } | |
90952d4e | 583 | |
584 | if(7*6 - res.monthData.length!=0){ //後補 | |
dbda9b49 | 585 | var nextYear = month+1>11 ? year+1 : year; |
586 | var nextMonth = month+1>11 ? 0 : month+1; | |
587 | var fillLen = 7*6 - res.monthData.length; | |
588 | nextMonthData = creatLenArr(nextYear,nextMonth+1,fillLen,1); | |
589 | res.monthData = res.monthData.concat(nextMonthData); | |
590 | } | |
591 | } | |
90952d4e | 592 | |
dbda9b49 | 593 | return res; |
594 | }; | |
90952d4e | 595 | |
dbda9b49 | 596 | /** |
90952d4e | 597 | * 設置放假安排【對外暴露接口】 |
dbda9b49 | 598 | * @param {Object} workData |
599 | */ | |
600 | function setWorktime(workData){ | |
601 | extend(worktime,workData); | |
602 | }; | |
603 | ||
604 | var LunarCalendar = { | |
605 | solarToLunar : solarToLunar, | |
606 | lunarToSolar : lunarToSolar, | |
607 | calendar : calendar, | |
608 | solarCalendar : solarCalendar, | |
e39c4564 JZ |
609 | setWorktime : setWorktime, |
610 | getSolarMonthDays : getSolarMonthDays | |
dbda9b49 | 611 | }; |
90952d4e | 612 | |
dbda9b49 | 613 | if (typeof define === 'function'){ |
614 | define (function (){ | |
615 | return LunarCalendar; | |
616 | }); | |
617 | }else if(typeof exports === 'object'){ | |
618 | module.exports = LunarCalendar; | |
619 | }else{ | |
620 | window.LunarCalendar = LunarCalendar; | |
621 | }; | |
622 | })(); |