2 * Copyright 2004 Ho Ngoc Duc [http://come.to/duc]. All Rights Reserved.<p>
\r
3 * Permission to use, copy, modify, and redistribute this software and its
\r
4 * documentation for personal, non-commercial use is hereby granted provided that
\r
5 * this copyright notice appears in all copies.
\r
8 var ABOUT = "\u00C2m l\u1ECBch Vi\u1EC7t Nam - Version 0.8"+"\n\u00A9 2004 H\u1ED3 Ng\u1ECDc \u0110\u1EE9c [http://come.to/duc]";
\r
9 var TK19 = new Array(
\r
10 0x30baa3, 0x56ab50, 0x422ba0, 0x2cab61, 0x52a370, 0x3c51e8, 0x60d160, 0x4ae4b0, 0x376926, 0x58daa0,
\r
11 0x445b50, 0x3116d2, 0x562ae0, 0x3ea2e0, 0x28e2d2, 0x4ec950, 0x38d556, 0x5cb520, 0x46b690, 0x325da4,
\r
12 0x5855d0, 0x4225d0, 0x2ca5b3, 0x52a2b0, 0x3da8b7, 0x60a950, 0x4ab4a0, 0x35b2a5, 0x5aad50, 0x4455b0,
\r
13 0x302b74, 0x562570, 0x4052f9, 0x6452b0, 0x4e6950, 0x386d56, 0x5e5aa0, 0x46ab50, 0x3256d4, 0x584ae0,
\r
14 0x42a570, 0x2d4553, 0x50d2a0, 0x3be8a7, 0x60d550, 0x4a5aa0, 0x34ada5, 0x5a95d0, 0x464ae0, 0x2eaab4,
\r
15 0x54a4d0, 0x3ed2b8, 0x64b290, 0x4cb550, 0x385757, 0x5e2da0, 0x4895d0, 0x324d75, 0x5849b0, 0x42a4b0,
\r
16 0x2da4b3, 0x506a90, 0x3aad98, 0x606b50, 0x4c2b60, 0x359365, 0x5a9370, 0x464970, 0x306964, 0x52e4a0,
\r
17 0x3cea6a, 0x62da90, 0x4e5ad0, 0x392ad6, 0x5e2ae0, 0x4892e0, 0x32cad5, 0x56c950, 0x40d4a0, 0x2bd4a3,
\r
18 0x50b690, 0x3a57a7, 0x6055b0, 0x4c25d0, 0x3695b5, 0x5a92b0, 0x44a950, 0x2ed954, 0x54b4a0, 0x3cb550,
\r
19 0x286b52, 0x4e55b0, 0x3a2776, 0x5e2570, 0x4852b0, 0x32aaa5, 0x56e950, 0x406aa0, 0x2abaa3, 0x50ab50
\r
20 ); /* Years 2000-2099 */
\r
22 var TK20 = new Array(
\r
23 0x3c4bd8, 0x624ae0, 0x4ca570, 0x3854d5, 0x5cd260, 0x44d950, 0x315554, 0x5656a0, 0x409ad0, 0x2a55d2,
\r
24 0x504ae0, 0x3aa5b6, 0x60a4d0, 0x48d250, 0x33d255, 0x58b540, 0x42d6a0, 0x2cada2, 0x5295b0, 0x3f4977,
\r
25 0x644970, 0x4ca4b0, 0x36b4b5, 0x5c6a50, 0x466d50, 0x312b54, 0x562b60, 0x409570, 0x2c52f2, 0x504970,
\r
26 0x3a6566, 0x5ed4a0, 0x48ea50, 0x336a95, 0x585ad0, 0x442b60, 0x2f86e3, 0x5292e0, 0x3dc8d7, 0x62c950,
\r
27 0x4cd4a0, 0x35d8a6, 0x5ab550, 0x4656a0, 0x31a5b4, 0x5625d0, 0x4092d0, 0x2ad2b2, 0x50a950, 0x38b557,
\r
28 0x5e6ca0, 0x48b550, 0x355355, 0x584da0, 0x42a5b0, 0x2f4573, 0x5452b0, 0x3ca9a8, 0x60e950, 0x4c6aa0,
\r
29 0x36aea6, 0x5aab50, 0x464b60, 0x30aae4, 0x56a570, 0x405260, 0x28f263, 0x4ed940, 0x38db47, 0x5cd6a0,
\r
30 0x4896d0, 0x344dd5, 0x5a4ad0, 0x42a4d0, 0x2cd4b4, 0x52b250, 0x3cd558, 0x60b540, 0x4ab5a0, 0x3755a6,
\r
31 0x5c95b0, 0x4649b0, 0x30a974, 0x56a4b0, 0x40aa50, 0x29aa52, 0x4e6d20, 0x39ad47, 0x5eab60, 0x489370,
\r
32 0x344af5, 0x5a4970, 0x4464b0, 0x2c74a3, 0x50ea50, 0x3d6a58, 0x6256a0, 0x4aaad0, 0x3696d5, 0x5c92e0
\r
33 ); /* Years 1900-1999 */
\r
35 var TK21 = new Array(
\r
36 0x46c960, 0x2ed954, 0x54d4a0, 0x3eda50, 0x2a7552, 0x4e56a0, 0x38a7a7, 0x5ea5d0, 0x4a92b0, 0x32aab5,
\r
37 0x58a950, 0x42b4a0, 0x2cbaa4, 0x50ad50, 0x3c55d9, 0x624ba0, 0x4ca5b0, 0x375176, 0x5c5270, 0x466930,
\r
38 0x307934, 0x546aa0, 0x3ead50, 0x2a5b52, 0x504b60, 0x38a6e6, 0x5ea4e0, 0x48d260, 0x32ea65, 0x56d520,
\r
39 0x40daa0, 0x2d56a3, 0x5256d0, 0x3c4afb, 0x6249d0, 0x4ca4d0, 0x37d0b6, 0x5ab250, 0x44b520, 0x2edd25,
\r
40 0x54b5a0, 0x3e55d0, 0x2a55b2, 0x5049b0, 0x3aa577, 0x5ea4b0, 0x48aa50, 0x33b255, 0x586d20, 0x40ad60,
\r
41 0x2d4b63, 0x525370, 0x3e49e8, 0x60c970, 0x4c54b0, 0x3768a6, 0x5ada50, 0x445aa0, 0x2fa6a4, 0x54aad0,
\r
42 0x4052e0, 0x28d2e3, 0x4ec950, 0x38d557, 0x5ed4a0, 0x46d950, 0x325d55, 0x5856a0, 0x42a6d0, 0x2c55d4,
\r
43 0x5252b0, 0x3ca9b8, 0x62a930, 0x4ab490, 0x34b6a6, 0x5aad50, 0x4655a0, 0x2eab64, 0x54a570, 0x4052b0,
\r
44 0x2ab173, 0x4e6930, 0x386b37, 0x5e6aa0, 0x48ad50, 0x332ad5, 0x582b60, 0x42a570, 0x2e52e4, 0x50d160,
\r
45 0x3ae958, 0x60d520, 0x4ada90, 0x355aa6, 0x5a56d0, 0x462ae0, 0x30a9d4, 0x54a2d0, 0x3ed150, 0x28e952
\r
46 ); /* Years 2000-2099 */
\r
48 var TK22 = new Array(
\r
49 0x4eb520, 0x38d727, 0x5eada0, 0x4a55b0, 0x362db5, 0x5a45b0, 0x44a2b0, 0x2eb2b4, 0x54a950, 0x3cb559,
\r
50 0x626b20, 0x4cad50, 0x385766, 0x5c5370, 0x484570, 0x326574, 0x5852b0, 0x406950, 0x2a7953, 0x505aa0,
\r
51 0x3baaa7, 0x5ea6d0, 0x4a4ae0, 0x35a2e5, 0x5aa550, 0x42d2a0, 0x2de2a4, 0x52d550, 0x3e5abb, 0x6256a0,
\r
52 0x4c96d0, 0x3949b6, 0x5e4ab0, 0x46a8d0, 0x30d4b5, 0x56b290, 0x40b550, 0x2a6d52, 0x504da0, 0x3b9567,
\r
53 0x609570, 0x4a49b0, 0x34a975, 0x5a64b0, 0x446a90, 0x2cba94, 0x526b50, 0x3e2b60, 0x28ab61, 0x4c9570,
\r
54 0x384ae6, 0x5cd160, 0x46e4a0, 0x2eed25, 0x54da90, 0x405b50, 0x2c36d3, 0x502ae0, 0x3a93d7, 0x6092d0,
\r
55 0x4ac950, 0x32d556, 0x58b4a0, 0x42b690, 0x2e5d94, 0x5255b0, 0x3e25fa, 0x6425b0, 0x4e92b0, 0x36aab6,
\r
56 0x5c6950, 0x4674a0, 0x31b2a5, 0x54ad50, 0x4055a0, 0x2aab73, 0x522570, 0x3a5377, 0x6052b0, 0x4a6950,
\r
57 0x346d56, 0x585aa0, 0x42ab50, 0x2e56d4, 0x544ae0, 0x3ca570, 0x2864d2, 0x4cd260, 0x36eaa6, 0x5ad550,
\r
58 0x465aa0, 0x30ada5, 0x5695d0, 0x404ad0, 0x2aa9b3, 0x50a4d0, 0x3ad2b7, 0x5eb250, 0x48b540, 0x33d556
\r
59 ); /* Years 2100-2199 */
\r
61 var CAN = new Array("Gi\341p", "\u1EA4t", "B\355nh", "\u0110inh", "M\u1EADu", "K\u1EF7", "Canh", "T\342n", "Nh\342m", "Qu\375");
\r
62 var CHI = new Array("T\375", "S\u1EEDu", "D\u1EA7n", "Mão", "Th\354n", "T\u1EF5", "Ng\u1ECD", "M\371i", "Th\342n", "D\u1EADu", "Tu\u1EA5t", "H\u1EE3i");
\r
63 var TUAN = new Array("Ch\u1EE7 Nh\u1EADt", "Th\u1EE9 Hai", "Th\u1EE9 Ba", "Th\u1EE9 T\u01B0", "Th\u1EE9 N\u0103m", "Th\u1EE9 S\341u", "Th\u1EE9 B\u1EA3y");
\r
64 var GIO_HD = new Array("110100101100", "001101001011", "110011010010", "101100110100", "001011001101", "010010110011");
\r
65 var TIETKHI = new Array("Xu\u00E2n ph\u00E2n", "Thanh minh", "C\u1ED1c v\u0169", "L\u1EADp h\u1EA1", "Ti\u1EC3u m\u00E3n", "Mang ch\u1EE7ng",
\r
66 "H\u1EA1 ch\u00ED", "Ti\u1EC3u th\u1EED", "\u0110\u1EA1i th\u1EED", "L\u1EADp thu", "X\u1EED th\u1EED", "B\u1EA1ch l\u1ED9",
\r
67 "Thu ph\u00E2n", "H\u00E0n l\u1ED9", "S\u01B0\u01A1ng gi\u00E1ng", "L\u1EADp \u0111\u00F4ng", "Ti\u1EC3u tuy\u1EBFt", "\u0110\u1EA1i tuy\u1EBFt",
\r
68 "\u0110\u00F4ng ch\u00ED", "Ti\u1EC3u h\u00E0n", "\u0110\u1EA1i h\u00E0n", "L\u1EADp xu\u00E2n", "V\u0169 Th\u1EE7y", "Kinh tr\u1EADp"
\r
73 /* Create lunar date object, stores (lunar) date, month, year, leap month indicator, and Julian date number */
\r
74 function LunarDate(dd, mm, yy, leap, jd) {
\r
84 /* Discard the fractional part of a number, e.g., INT(3.2) = 3 */
\r
86 return Math.floor(d);
\r
89 function jdn(dd, mm, yy) {
\r
90 var a = INT((14 - mm) / 12);
\r
93 var jd = dd + INT((153*m+2)/5) + 365*y + INT(y/4) - INT(y/100) + INT(y/400) - 32045;
\r
95 //return 367*yy - INT(7*(yy+INT((mm+9)/12))/4) - INT(3*(INT((yy+(mm-9)/7)/100)+1)/4) + INT(275*mm/9)+dd+1721029;
\r
98 function jdn2date(jd) {
\r
99 var Z, A, alpha, B, C, D, E, dd, mm, yyyy, F;
\r
104 alpha = INT((Z-1867216.25)/36524.25);
\r
105 A = Z + 1 + alpha - INT(alpha/4);
\r
108 C = INT( (B-122.1)/365.25);
\r
109 D = INT( 365.25*C );
\r
110 E = INT( (B-D)/30.6001 );
\r
111 dd = INT(B - D - INT(30.6001*E));
\r
122 return new Array(dd, mm, yyyy);
\r
125 function decodeLunarYear(yy, k) {
\r
126 var monthLengths, regularMonths, offsetOfTet, leapMonth, leapMonthLength, solarNY, currentJD, j, mm;
\r
127 var ly = new Array();
\r
128 monthLengths = new Array(29, 30);
\r
129 var regularMonths = new Array(12);
\r
130 offsetOfTet = k >> 17;
\r
131 leapMonth = k & 0xf;
\r
132 leapMonthLength = monthLengths[k >> 16 & 0x1];
\r
133 solarNY = jdn(1, 1, yy);
\r
134 currentJD = solarNY+offsetOfTet;
\r
136 for(var i = 0; i < 12; i++) {
\r
137 regularMonths[12 - i - 1] = monthLengths[j & 0x1];
\r
140 if (leapMonth == 0) {
\r
141 for(mm = 1; mm <= 12; mm++) {
\r
142 ly.push(new LunarDate(1, mm, yy, 0, currentJD));
\r
143 currentJD += regularMonths[mm-1];
\r
146 for(mm = 1; mm <= leapMonth; mm++) {
\r
147 ly.push(new LunarDate(1, mm, yy, 0, currentJD));
\r
148 currentJD += regularMonths[mm-1];
\r
150 ly.push(new LunarDate(1, leapMonth, yy, 1, currentJD));
\r
151 currentJD += leapMonthLength;
\r
152 for(mm = leapMonth+1; mm <= 12; mm++) {
\r
153 ly.push(new LunarDate(1, mm, yy, 0, currentJD));
\r
154 currentJD += regularMonths[mm-1];
\r
158 LML = leapMonthLength;
\r
159 RMM = regularMonths;
\r
164 function leapMonth(yyyy){
\r
165 var yearCode = getYearCode(yyyy);
\r
166 return yearCode & 0xf;
\r
169 function monthLength(yyyy){
\r
170 var yearCode = getYearCode(yyyy);
\r
171 return yearCode >> 16 & 0x1;
\r
174 function getYearCode(yyyy){
\r
177 yearCode = TK19[yyyy - 1800];
\r
178 } else if (yyyy < 2000) {
\r
179 yearCode = TK20[yyyy - 1900];
\r
180 } else if (yyyy < 2100) {
\r
181 yearCode = TK21[yyyy - 2000];
\r
183 yearCode = TK22[yyyy - 2100];
\r
188 function getYearInfo(yyyy) {
\r
191 yearCode = TK19[yyyy - 1800];
\r
192 } else if (yyyy < 2000) {
\r
193 yearCode = TK20[yyyy - 1900];
\r
194 } else if (yyyy < 2100) {
\r
195 yearCode = TK21[yyyy - 2000];
\r
197 yearCode = TK22[yyyy - 2100];
\r
199 return decodeLunarYear(yyyy, yearCode);
\r
202 var FIRST_DAY = jdn(25, 1, 1800); // Tet am lich 1800
\r
203 var LAST_DAY = jdn(31, 12, 2199);
\r
206 function findLunarDate(jd, ly) {
\r
207 if (jd > LAST_DAY || jd < FIRST_DAY || ly[0].jd > jd) {
\r
208 return new LunarDate(0, 0, 0, 0, jd);
\r
210 var i = ly.length-1;
\r
211 while (jd < ly[i].jd) {
\r
214 var off = jd - ly[i].jd;
\r
215 var ret = new LunarDate(ly[i].day+off, ly[i].month, ly[i].year, ly[i].leap, jd);
\r
220 function getLunarDate(dd, mm, yyyy) {
\r
222 if (yyyy < 1800 || 2199 < yyyy) {
\r
223 //return new LunarDate(0, 0, 0, 0, 0);
\r
225 ly = getYearInfo(yyyy);
\r
226 jd = jdn(dd, mm, yyyy);
\r
227 if (jd < ly[0].jd) {
\r
228 ly = getYearInfo(yyyy - 1);
\r
230 return findLunarDate(jd, ly);
\r
233 /* Compute the longitude of the sun at any time.
\r
234 * Parameter: floating number jdn, the number of days since 1/1/4713 BC noon
\r
235 * Algorithm from: "Astronomical Algorithms" by Jean Meeus, 1998
\r
237 function SunLongitude(jdn) {
\r
238 var T, T2, dr, M, L0, DL, lambda, theta, omega;
\r
239 T = (jdn - 2451545.0 ) / 36525; // Time in Julian centuries from 2000-01-01 12:00:00 GMT
\r
241 dr = PI/180; // degree to radian
\r
242 M = 357.52910 + 35999.05030*T - 0.0001559*T2 - 0.00000048*T*T2; // mean anomaly, degree
\r
243 L0 = 280.46645 + 36000.76983*T + 0.0003032*T2; // mean longitude, degree
\r
244 DL = (1.914600 - 0.004817*T - 0.000014*T2)*Math.sin(dr*M);
\r
245 DL = DL + (0.019993 - 0.000101*T)*Math.sin(dr*2*M) + 0.000290*Math.sin(dr*3*M);
\r
246 theta = L0 + DL; // true longitude, degree
\r
247 // obtain apparent longitude by correcting for nutation and aberration
\r
248 omega = 125.04 - 1934.136 * T;
\r
249 lambda = theta - 0.00569 - 0.00478 * Math.sin(omega * dr);
\r
250 // Convert to radians
\r
251 lambda = lambda*dr;
\r
252 lambda = lambda - PI*2*(INT(lambda/(PI*2))); // Normalize to (0, 2*PI)
\r
256 /* Compute the sun segment at start (00:00) of the day with the given integral Julian day number.
\r
257 * The time zone if the time difference between local time and UTC: 7.0 for UTC+7:00.
\r
258 * The function returns a number between 0 and 23.
\r
259 * From the day after March equinox and the 1st major term after March equinox, 0 is returned.
\r
260 * After that, return 1, 2, 3 ...
\r
262 function getSunLongitude(dayNumber, timeZone) {
\r
263 return INT(SunLongitude(dayNumber - 0.5 - timeZone/24.0) / PI * 12);
\r
266 var today = new Date();
\r
267 //var currentLunarYear = getYearInfo(today.getFullYear());
\r
268 var currentLunarDate = getLunarDate(today.getDate(), today.getMonth()+1, today.getFullYear());
\r
269 var currentMonth = today.getMonth()+1;
\r
270 var currentYear = today.getFullYear();
\r
272 function parseQuery(q) {
\r
273 var ret = new Array();
\r
274 if (q.length < 2) return ret;
\r
275 var s = q.substring(1, q.length);
\r
276 var arr = s.split("&");
\r
278 for (i = 0; i < arr.length; i++) {
\r
279 var a = arr[i].split("=");
\r
280 for (j = 0; j < a.length; j++) {
\r
287 function getSelectedMonth() {
\r
288 var query = window.location.search;
\r
289 var arr = parseQuery(query);
\r
291 for (idx = 0; idx < arr.length; idx++) {
\r
292 if (arr[idx] == "mm") {
\r
293 currentMonth = parseInt(arr[idx+1]);
\r
294 } else if (arr[idx] == "yy") {
\r
295 currentYear = parseInt(arr[idx+1]);
\r
300 function getMonth(mm, yy) {
\r
301 var ly1, ly2, tet1, jd1, jd2, mm1, yy1, result, i;
\r
309 jd1 = jdn(1, mm, yy);
\r
310 jd2 = jdn(1, mm1, yy1);
\r
311 ly1 = getYearInfo(yy);
\r
312 //alert('1/'+mm+'/'+yy+' = '+jd1+'; 1/'+mm1+'/'+yy1+' = '+jd2);
\r
314 result = new Array();
\r
315 if (tet1 <= jd1) { /* tet(yy) = tet1 < jd1 < jd2 <= 1.1.(yy+1) < tet(yy+1) */
\r
316 for (i = jd1; i < jd2; i++) {
\r
317 result.push(findLunarDate(i, ly1));
\r
319 } else if (jd1 < tet1 && jd2 < tet1) { /* tet(yy-1) < jd1 < jd2 < tet1 = tet(yy) */
\r
320 ly1 = getYearInfo(yy - 1);
\r
321 for (i = jd1; i < jd2; i++) {
\r
322 result.push(findLunarDate(i, ly1));
\r
324 } else if (jd1 < tet1 && tet1 <= jd2) { /* tet(yy-1) < jd1 < tet1 <= jd2 < tet(yy+1) */
\r
325 ly2 = getYearInfo(yy - 1);
\r
326 for (i = jd1; i < tet1; i++) {
\r
327 result.push(findLunarDate(i, ly2));
\r
329 for (i = tet1; i < jd2; i++) {
\r
330 result.push(findLunarDate(i, ly1));
\r
336 function getDayName(lunarDate) {
\r
337 if (lunarDate.day == 0) {
\r
340 var cc = getCanChi(lunarDate);
\r
341 var s = "Ng\u00E0y " + cc[0] +", th\341ng "+cc[1] + ", n\u0103m " + cc[2];
\r
345 function getYearCanChi(year) {
\r
346 return CAN[(year+6) % 10] + " " + CHI[(year+8) % 12];
\r
350 * Can cua gio Chinh Ty (00:00) cua ngay voi JDN nay
\r
352 function getCanHour0(jdn) {
\r
353 return CAN[(jdn-1)*2 % 10];
\r
356 function getCanChi(lunar) {
\r
357 var dayName, monthName, yearName;
\r
358 dayName = CAN[(lunar.jd + 9) % 10] + " " + CHI[(lunar.jd+1)%12];
\r
359 monthName = CAN[(lunar.year*12+lunar.month+3) % 10] + " " + CHI[(lunar.month+1)%12];
\r
360 if (lunar.leap == 1) {
\r
361 monthName += " (N)";
\r
363 yearName = getYearCanChi(lunar.year);
\r
364 return new Array(dayName, monthName, yearName);
\r
367 function getDayString(lunar, solarDay, solarMonth, solarYear) {
\r
369 var dayOfWeek = TUAN[(lunar.jd + 1) % 7];
\r
370 s = dayOfWeek + " " + solarDay + "/" + solarMonth + "/" + solarYear;
\r
372 s = s + "Ng\u00E0y " + lunar.day+" th\341ng "+lunar.month;
\r
373 if (lunar.leap == 1) {
\r
374 s = s + " nhu\u1EADn";
\r
379 function getTodayString() {
\r
380 var s = getDayString(currentLunarDate, today.getDate(), today.getMonth()+1, today.getFullYear());
\r
381 s += " n\u0103m " + getYearCanChi(currentLunarDate.year);
\r
385 function getCurrentTime() {
\r
386 today = new Date();
\r
387 var Std = today.getHours();
\r
388 var Min = today.getMinutes();
\r
389 var Sec = today.getSeconds();
\r
390 var s1 = ((Std < 10) ? "0" + Std : Std);
\r
391 var s2 = ((Min < 10) ? "0" + Min : Min);
\r
392 //var s3 = ((Sec < 10) ? "0" + Sec : Sec);
\r
393 //return s1 + ":" + s2 + ":" + s3;
\r
394 return s1 + ":" + s2;
\r
397 function getGioHoangDao(jd) {
\r
398 var chiOfDay = (jd+1) % 12;
\r
399 var gioHD = GIO_HD[chiOfDay % 6]; // same values for Ty' (1) and Ngo. (6), for Suu and Mui etc.
\r
402 for (var i = 0; i < 12; i++) {
\r
403 if (gioHD.charAt(i) == '1') {
\r
405 ret += ' ('+(i*2+23)%24+'h-'+(i*2+1)%24+'h)';
\r
406 if (count++ < 5) ret += ', ';
\r
407 if (count == 3) ret += '<br>';
\r
413 function getTHU(jd){
\r
414 return TUAN[(jd+1)%7];
\r
417 function getTHUINT(jd){
\r