Commit | Line | Data |
---|---|---|
dbda9b49 | 1 | /** |
2 | * 农历(阴历)万年历 | |
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 | }; | |
20 | ||
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 | }; | |
32 | ||
33 | var errorCode = { //错误码列表 | |
34 | 100 : '输入的年份超过了可查询范围,仅支持1891至2100年', | |
35 | 101 : '参数输入错误,请查阅文档' | |
36 | }; | |
37 | ||
38 | var cache = null; //某年相同计算进行cache,以加速计算速度 | |
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 | }; | |
60 | ||
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 | }; | |
67 | ||
68 | var minYear = 1890;//最小年限 | |
69 | var maxYear = 2100;//最大年限 | |
70 | var DATA = { | |
71 | heavenlyStems: ['甲', '乙', '丙', '丁', '戊', '己', '庚', '辛', '壬', '癸'], //天干 | |
72 | earthlyBranches: ['子', '丑', '寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌', '亥'], //地支 | |
73 | zodiac: ['鼠','牛','虎','兔','龙','蛇','马','羊','猴','鸡','狗','猪'], //对应地支十二生肖 | |
74 | solarTerm: ['小寒', '大寒', '立春', '雨水', '惊蛰', '春分', '清明', '谷雨', '立夏', '小满', '芒种', '夏至', '小暑', '大暑', '立秋', '处暑', '白露', '秋分', '寒露', '霜降', '立冬', '小雪', '大雪','冬至'], //二十四节气 | |
75 | monthCn: ['正', '二', '三', '四', '五', '六', '七', '八', '九', '十', '十一', '十二'], | |
76 | dateCn: ['初一', '初二', '初三', '初四', '初五', '初六', '初七', '初八', '初九', '初十', '十一', '十二', '十三', '十四', '十五', '十六', '十七', '十八', '十九', '二十', '廿一', '廿二', '廿三', '廿四', '廿五', '廿六', '廿七', '廿八', '廿九', '三十', '卅一'] | |
77 | }; | |
78 | ||
79 | //中国节日放假安排,外部设置,0无特殊安排,1工作,2放假 | |
80 | var worktime = {}; | |
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 | //公历节日 | |
86 | var solarFestival = { | |
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':'世界森林日 消除种族歧视国际日 世界儿歌日', | |
100 | 'd0322':'世界水日', | |
101 | 'd0323':'世界气象日', | |
102 | 'd0324':'世界防治结核病日', | |
103 | 'd0325':'全国中小学生安全教育日', | |
104 | 'd0330':'巴勒斯坦国土日', | |
105 | 'd0401':'愚人节 全国爱国卫生运动月(四月) 税收宣传月(四月)', | |
106 | 'd0407':'世界卫生日', | |
107 | 'd0422':'世界地球日', | |
108 | 'd0423':'世界图书和版权日', | |
109 | 'd0424':'亚非新闻工作者日', | |
110 | 'd0501':'劳动节', | |
111 | 'd0504':'青年节', | |
112 | 'd0505':'碘缺乏病防治日', | |
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':'抗日战争纪念日', | |
132 | 'd0711':'世界人口日', | |
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':'孙中山诞辰纪念日', | |
167 | 'd1114':'世界糖尿病日', | |
168 | 'd1117':'国际大学生节 世界学生节', | |
169 | 'd1121':'世界问候日 世界电视日', | |
170 | 'd1129':'国际声援巴勒斯坦人民国际日', | |
171 | 'd1201':'世界艾滋病日', | |
172 | 'd1203':'世界残疾人日', | |
173 | 'd1205':'国际经济和社会发展志愿人员日', | |
174 | 'd1208':'国际儿童电视日', | |
175 | 'd1209':'世界足球日', | |
176 | 'd1210':'世界人权日', | |
177 | 'd1212':'西安事变纪念日', | |
178 | 'd1213':'南京大屠杀(1937年)纪念日!紧记血泪史!', | |
179 | 'd1220':'澳门回归纪念', | |
180 | 'd1221':'国际篮球日', | |
181 | 'd1224':'平安夜', | |
182 | 'd1225':'圣诞节', | |
183 | 'd1226':'毛泽东诞辰纪念' | |
184 | }; | |
185 | ||
186 | //农历节日 | |
187 | var lunarFestival = { | |
188 | 'd0101':'春节', | |
189 | 'd0115':'元宵节', | |
190 | 'd0202':'龙抬头节', | |
191 | 'd0323':'妈祖生辰', | |
192 | 'd0505':'端午节', | |
193 | 'd0707':'七夕情人节', | |
194 | 'd0715':'中元节', | |
195 | 'd0815':'中秋节', | |
196 | 'd0909':'重阳节', | |
197 | 'd1015':'下元节', | |
198 | 'd1208':'腊八节', | |
199 | 'd1223':'小年', | |
200 | 'd0100':'除夕' | |
201 | } | |
202 | ||
203 | /** | |
204 | * 1890 - 2100 年的农历数据 | |
205 | * 数据格式:[0,2,9,21936] | |
206 | * [闰月所在月,0为没有闰月; *正月初一对应公历月; *正月初一对应公历日; *农历每月的天数的数组(需转换为二进制,得到每月大小,0=小月(29日),1=大月(30日));] | |
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]]; | |
209 | ||
210 | /** | |
211 | * 二十四节气数据,节气点时间(单位是分钟) | |
212 | * 从0小寒起算 | |
213 | */ | |
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 | ||
216 | /** | |
217 | * 判断农历年闰月数 | |
218 | * @param {Number} year 农历年 | |
219 | * return 闰月数 (月份从1开始) | |
220 | */ | |
221 | function getLunarLeapYear(year){ | |
222 | var yearData = lunarInfo[year-minYear]; | |
223 | return yearData[0]; | |
224 | }; | |
225 | ||
226 | /** | |
227 | * 获取农历年份一年的每月的天数及一年的总天数 | |
228 | * @param {Number} year 农历年 | |
229 | */ | |
230 | function getLunarYearDays(year){ | |
231 | var yearData = lunarInfo[year-minYear]; | |
232 | var leapMonth = yearData[0]; //闰月 | |
233 | var monthData = yearData[3].toString(2); | |
234 | var monthDataArr = monthData.split(''); | |
235 | ||
236 | //还原数据至16位,少于16位的在前面插入0(二进制存储时前面的0被忽略) | |
237 | for(var i=0;i<16-monthDataArr.length;i++){ | |
238 | monthDataArr.unshift(0); | |
239 | } | |
240 | ||
241 | var len = leapMonth ? 13 : 12; //该年有几个月 | |
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 | } | |
253 | ||
254 | return { | |
255 | yearDays : yearDays, | |
256 | monthDays : monthDays | |
257 | }; | |
258 | }; | |
259 | ||
260 | /** | |
261 | * 通过间隔天数查找农历日期 | |
262 | * @param {Number} year,between 农历年,间隔天数 | |
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 | } | |
278 | ||
279 | return [year,month,end - tempDays + 1]; | |
280 | }; | |
281 | ||
282 | /** | |
283 | * 根据距离正月初一的天数计算农历日期 | |
284 | * @param {Number} year 公历年,月,日 | |
285 | */ | |
286 | function getLunarByBetween(year,month,day){ | |
287 | var yearData = lunarInfo[year-minYear]; | |
288 | var zenMonth = yearData[1]; | |
289 | var zenDay = yearData[2]; | |
290 | var between = getDaysBetweenSolar(year,zenMonth-1,zenDay,year,month,day); | |
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 | }; | |
298 | ||
299 | /** | |
300 | * 两个公历日期之间的天数 | |
301 | */ | |
302 | function getDaysBetweenSolar(year,month,day,year1,month1,day1){ | |
303 | var date = new Date(year,month,day).getTime(); | |
304 | var date1 = new Date(year1,month1,day1).getTime(); | |
305 | return (date1-date) / 86400000; | |
306 | }; | |
307 | ||
308 | /** | |
309 | * 计算农历日期离正月初一有多少天 | |
310 | * @param {Number} year,month,day 农年,月(0-12,有闰月),日 | |
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 | }; | |
325 | ||
326 | /** | |
327 | * 某年的第n个节气为几日 | |
328 | * 31556925974.7为地球公转周期,是毫秒 | |
329 | * 1890年的正小寒点:01-05 16:02:31,1890年为基准点 | |
330 | * @param {Number} y 公历年 | |
331 | * @param {Number} n 第几个节气,从0小寒起算 | |
adce4586 | 332 | * 由于农历24节气交节时刻采用近似算法,可能存在少量误差(30分钟内) |
dbda9b49 | 333 | */ |
334 | function getTerm(y,n) { | |
335 | var offDate = new Date( ( 31556925974.7*(y-1890) + termInfo[n]*60000 ) + Date.UTC(1890,0,5,16,2,31) ); | |
336 | return(offDate.getUTCDate()); | |
337 | }; | |
338 | ||
339 | /** | |
340 | * 获取公历年一年的二十四节气 | |
341 | * 返回key:日期,value:节气中文名 | |
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 | }; | |
353 | ||
354 | /** | |
355 | * 获取生肖 | |
356 | * @param {Number} year 干支所在年(默认以立春前的公历年作为基数) | |
357 | */ | |
358 | function getYearZodiac(year){ | |
359 | var num = year-1890+25; //参考干支纪年的计算,生肖对应地支 | |
360 | return DATA.zodiac[num%12]; | |
361 | }; | |
362 | ||
363 | /** | |
364 | * 计算天干地支 | |
365 | * @param {Number} num 60进制中的位置(把60个天干地支,当成一个60进制的数) | |
366 | */ | |
367 | function cyclical(num) { | |
368 | return(DATA.heavenlyStems[num%10]+DATA.earthlyBranches[num%12]); | |
369 | } | |
370 | ||
371 | /** | |
372 | * 获取干支纪年 | |
373 | * @param {Number} year 干支所在年 | |
374 | * @param {Number} offset 偏移量,默认为0,便于查询一个年跨两个干支纪年(以立春为分界线) | |
375 | */ | |
376 | function getLunarYearName(year,offset){ | |
377 | offset = offset || 0; | |
378 | //1890年1月小寒(小寒一般是1月5或6日)以前为己丑年,在60进制中排25 | |
379 | return cyclical(year-1890+25+offset); | |
380 | }; | |
381 | ||
382 | /** | |
383 | * 获取干支纪月 | |
384 | * @param {Number} year,month 公历年,干支所在月 | |
385 | * @param {Number} offset 偏移量,默认为0,便于查询一个月跨两个干支纪月(有立春的2月) | |
386 | */ | |
387 | function getLunarMonthName(year,month,offset){ | |
388 | offset = offset || 0; | |
389 | //1890年1月小寒以前为丙子月,在60进制中排12 | |
390 | return cyclical((year-1890)*12+month+12+offset); | |
391 | }; | |
392 | ||
393 | /** | |
394 | * 获取干支纪日 | |
395 | * @param {Number} year,month,day 公历年,月,日 | |
396 | */ | |
397 | function getLunarDayName(year,month,day){ | |
398 | //当日与1890/1/1 相差天数 | |
399 | //1890/1/1与 1970/1/1 相差29219日, 1890/1/1 日柱为壬午日(60进制18) | |
400 | var dayCyclical = Date.UTC(year,month,day)/86400000+29219+18; | |
401 | return cyclical(dayCyclical); | |
402 | }; | |
403 | ||
404 | /** | |
405 | * 获取公历月份的天数 | |
406 | * @param {Number} year 公历年 | |
407 | * @param {Number} month 公历月 | |
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 | }; | |
413 | ||
414 | /** | |
415 | * 判断公历年是否是闰年 | |
416 | * @param {Number} year 公历年 | |
417 | */ | |
418 | function isLeapYear(year){ | |
419 | return ((year%4==0 && year%100 !=0) || (year%400==0)); | |
420 | }; | |
421 | ||
422 | /* | |
423 | * 统一日期输入参数(输入月份从1开始,内部月份统一从0开始) | |
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 | }; | |
438 | ||
439 | /** | |
440 | * 将农历转换为公历 | |
441 | * @param {Number} year,month,day 农历年,月(1-13,有闰月),日 | |
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; | |
449 | ||
450 | var between = getDaysBetweenZheng(year,month,day); //离正月初一的天数 | |
451 | var yearData = lunarInfo[year-minYear]; | |
452 | var zenMonth = yearData[1]; | |
453 | var zenDay = yearData[2]; | |
454 | ||
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 | }; | |
463 | ||
464 | /** | |
465 | * 将公历转换为农历 | |
466 | * @param {Number} year,month,day 公历年,月,日 | |
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; | |
474 | ||
475 | cacheUtil.setCurrent(year); | |
476 | //立春日期 | |
477 | var term2 = cacheUtil.get('term2') ? cacheUtil.get('term2') : cacheUtil.set('term2',getTerm(year,2)); | |
478 | //二十四节气 | |
479 | var termList = cacheUtil.get('termList') ? cacheUtil.get('termList') : cacheUtil.set('termList',getYearTerm(year)); | |
480 | ||
481 | var firstTerm = getTerm(year,month*2); //某月第一个节气开始日期 | |
482 | var GanZhiYear = (month>1 || month==1 && day>=term2) ? year+1 : year;//干支所在年份 | |
483 | var GanZhiMonth = day>=firstTerm ? month+1 : month; //干支所在月份(以节气为界) | |
484 | ||
485 | var lunarDate = getLunarByBetween(year,month,day); | |
486 | var lunarLeapMonth = getLunarLeapYear(lunarDate[0]); | |
487 | var lunarMonthName = ''; | |
488 | if(lunarLeapMonth>0 && lunarLeapMonth==lunarDate[1]){ | |
489 | lunarMonthName = '闰'+DATA.monthCn[lunarDate[1]-1]+'月'; | |
490 | }else if(lunarLeapMonth>0 && lunarDate[1]>lunarLeapMonth){ | |
491 | lunarMonthName = DATA.monthCn[lunarDate[1]-1]+'月'; | |
492 | }else{ | |
493 | lunarMonthName = DATA.monthCn[lunarDate[1]]+'月'; | |
494 | } | |
495 | ||
496 | //农历节日判断 | |
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 | } | |
507 | ||
508 | var res = { | |
509 | zodiac : getYearZodiac(GanZhiYear), | |
510 | GanZhiYear : getLunarYearName(GanZhiYear), | |
511 | GanZhiMonth : getLunarMonthName(year,GanZhiMonth), | |
512 | GanZhiDay : getLunarDayName(year,month,day), | |
513 | //放假安排:0无特殊安排,1工作,2放假 | |
514 | worktime : worktime['y'+year] && worktime['y'+year][formateDayD4(month,day)] ? worktime['y'+year][formateDayD4(month,day)] : 0, | |
515 | term : termList[formateDayD4(month,day)], | |
516 | ||
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, | |
523 | ||
524 | solarFestival : solarFestival[formateDayD4(month,day)], | |
525 | lunarFestival : lunarFtv | |
526 | }; | |
527 | ||
528 | return res; | |
529 | }; | |
530 | ||
531 | /** | |
532 | * 获取指定公历月份的农历数据 | |
533 | * return res{Object} | |
534 | * @param {Number} year,month 公历年,月 | |
535 | * @param {Boolean} fill 是否用上下月数据补齐首尾空缺,首例数据从周日开始 | |
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; | |
542 | ||
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 | }; | |
551 | ||
552 | /** | |
553 | * 公历某月日历 | |
554 | * return res{Object} | |
555 | * @param {Number} year,month 公历年,月 | |
556 | * @param {Boolean} fill 是否用上下月数据补齐首尾空缺,首例数据从周日开始 (7*6阵列) | |
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; | |
563 | ||
740058ad | 564 | var firstDate = new Date(year,month,1); |
dbda9b49 | 565 | var preMonthDays,preMonthData,nextMonthData; |
566 | ||
567 | var res = { | |
568 | firstDay : firstDate.getDay(), //该月1号星期几 | |
569 | monthDays : getSolarMonthDays(year,month), //该月天数 | |
570 | monthData : [] | |
571 | }; | |
572 | ||
573 | res.monthData = creatLenArr(year,month+1,res.monthDays,1); | |
574 | ||
575 | if(fill){ | |
576 | if(res.firstDay > 0){ //前补 | |
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 | } | |
583 | ||
584 | if(7*6 - res.monthData.length!=0){ //后补 | |
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 | } | |
592 | ||
593 | return res; | |
594 | }; | |
595 | ||
596 | /** | |
597 | * 设置放假安排【对外暴露接口】 | |
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 | }; |
612 | ||
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 | })(); |