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
163 function leapMonth(yyyy){
\r
164 var yearCode = getYearCode(yyyy);
\r
165 return yearCode & 0xf;
\r
168 function monthLength(yyyy){
\r
169 var yearCode = getYearCode(yyyy);
\r
170 return yearCode >> 16 & 0x1;
\r
173 function getYearCode(yyyy){
\r
176 yearCode = TK19[yyyy - 1800];
\r
177 } else if (yyyy < 2000) {
\r
178 yearCode = TK20[yyyy - 1900];
\r
179 } else if (yyyy < 2100) {
\r
180 yearCode = TK21[yyyy - 2000];
\r
182 yearCode = TK22[yyyy - 2100];
\r
187 function getYearInfo(yyyy) {
\r
190 yearCode = TK19[yyyy - 1800];
\r
191 } else if (yyyy < 2000) {
\r
192 yearCode = TK20[yyyy - 1900];
\r
193 } else if (yyyy < 2100) {
\r
194 yearCode = TK21[yyyy - 2000];
\r
196 yearCode = TK22[yyyy - 2100];
\r
198 return decodeLunarYear(yyyy, yearCode);
\r
201 var FIRST_DAY = jdn(25, 1, 1800); // Tet am lich 1800
\r
202 var LAST_DAY = jdn(31, 12, 2199);
\r
204 function findLunarDate(jd, ly) {
\r
205 if (jd > LAST_DAY || jd < FIRST_DAY || ly[0].jd > jd) {
\r
206 return new LunarDate(0, 0, 0, 0, jd);
\r
208 var i = ly.length-1;
\r
209 while (jd < ly[i].jd) {
\r
212 var off = jd - ly[i].jd;
\r
213 var ret = new LunarDate(ly[i].day+off, ly[i].month, ly[i].year, ly[i].leap, jd);
\r
217 function getLunarDate(dd, mm, yyyy) {
\r
219 if (yyyy < 1800 || 2199 < yyyy) {
\r
220 //return new LunarDate(0, 0, 0, 0, 0);
\r
222 ly = getYearInfo(yyyy);
\r
223 jd = jdn(dd, mm, yyyy);
\r
224 if (jd < ly[0].jd) {
\r
225 ly = getYearInfo(yyyy - 1);
\r
227 return findLunarDate(jd, ly);
\r
230 /* Compute the longitude of the sun at any time.
\r
231 * Parameter: floating number jdn, the number of days since 1/1/4713 BC noon
\r
232 * Algorithm from: "Astronomical Algorithms" by Jean Meeus, 1998
\r
234 function SunLongitude(jdn) {
\r
235 var T, T2, dr, M, L0, DL, lambda, theta, omega;
\r
236 T = (jdn - 2451545.0 ) / 36525; // Time in Julian centuries from 2000-01-01 12:00:00 GMT
\r
238 dr = PI/180; // degree to radian
\r
239 M = 357.52910 + 35999.05030*T - 0.0001559*T2 - 0.00000048*T*T2; // mean anomaly, degree
\r
240 L0 = 280.46645 + 36000.76983*T + 0.0003032*T2; // mean longitude, degree
\r
241 DL = (1.914600 - 0.004817*T - 0.000014*T2)*Math.sin(dr*M);
\r
242 DL = DL + (0.019993 - 0.000101*T)*Math.sin(dr*2*M) + 0.000290*Math.sin(dr*3*M);
\r
243 theta = L0 + DL; // true longitude, degree
\r
244 // obtain apparent longitude by correcting for nutation and aberration
\r
245 omega = 125.04 - 1934.136 * T;
\r
246 lambda = theta - 0.00569 - 0.00478 * Math.sin(omega * dr);
\r
247 // Convert to radians
\r
248 lambda = lambda*dr;
\r
249 lambda = lambda - PI*2*(INT(lambda/(PI*2))); // Normalize to (0, 2*PI)
\r
253 /* Compute the sun segment at start (00:00) of the day with the given integral Julian day number.
\r
254 * The time zone if the time difference between local time and UTC: 7.0 for UTC+7:00.
\r
255 * The function returns a number between 0 and 23.
\r
256 * From the day after March equinox and the 1st major term after March equinox, 0 is returned.
\r
257 * After that, return 1, 2, 3 ...
\r
259 function getSunLongitude(dayNumber, timeZone) {
\r
260 return INT(SunLongitude(dayNumber - 0.5 - timeZone/24.0) / PI * 12);
\r
263 var today = new Date();
\r
264 //var currentLunarYear = getYearInfo(today.getFullYear());
\r
265 var currentLunarDate = getLunarDate(today.getDate(), today.getMonth()+1, today.getFullYear());
\r
266 var currentMonth = today.getMonth()+1;
\r
267 var currentYear = today.getFullYear();
\r
269 function parseQuery(q) {
\r
270 var ret = new Array();
\r
271 if (q.length < 2) return ret;
\r
272 var s = q.substring(1, q.length);
\r
273 var arr = s.split("&");
\r
275 for (i = 0; i < arr.length; i++) {
\r
276 var a = arr[i].split("=");
\r
277 for (j = 0; j < a.length; j++) {
\r
284 function getSelectedMonth() {
\r
285 var query = window.location.search;
\r
286 var arr = parseQuery(query);
\r
288 for (idx = 0; idx < arr.length; idx++) {
\r
289 if (arr[idx] == "mm") {
\r
290 currentMonth = parseInt(arr[idx+1]);
\r
291 } else if (arr[idx] == "yy") {
\r
292 currentYear = parseInt(arr[idx+1]);
\r
297 function getMonth(mm, yy) {
\r
298 var ly1, ly2, tet1, jd1, jd2, mm1, yy1, result, i;
\r
306 jd1 = jdn(1, mm, yy);
\r
307 jd2 = jdn(1, mm1, yy1);
\r
308 ly1 = getYearInfo(yy);
\r
309 //alert('1/'+mm+'/'+yy+' = '+jd1+'; 1/'+mm1+'/'+yy1+' = '+jd2);
\r
311 result = new Array();
\r
312 if (tet1 <= jd1) { /* tet(yy) = tet1 < jd1 < jd2 <= 1.1.(yy+1) < tet(yy+1) */
\r
313 for (i = jd1; i < jd2; i++) {
\r
314 result.push(findLunarDate(i, ly1));
\r
316 } else if (jd1 < tet1 && jd2 < tet1) { /* tet(yy-1) < jd1 < jd2 < tet1 = tet(yy) */
\r
317 ly1 = getYearInfo(yy - 1);
\r
318 for (i = jd1; i < jd2; i++) {
\r
319 result.push(findLunarDate(i, ly1));
\r
321 } else if (jd1 < tet1 && tet1 <= jd2) { /* tet(yy-1) < jd1 < tet1 <= jd2 < tet(yy+1) */
\r
322 ly2 = getYearInfo(yy - 1);
\r
323 for (i = jd1; i < tet1; i++) {
\r
324 result.push(findLunarDate(i, ly2));
\r
326 for (i = tet1; i < jd2; i++) {
\r
327 result.push(findLunarDate(i, ly1));
\r
333 function getDayName(lunarDate) {
\r
334 if (lunarDate.day == 0) {
\r
337 var cc = getCanChi(lunarDate);
\r
338 var s = "Ng\u00E0y " + cc[0] +", th\341ng "+cc[1] + ", n\u0103m " + cc[2];
\r
342 function getYearCanChi(year) {
\r
343 return CAN[(year+6) % 10] + " " + CHI[(year+8) % 12];
\r
347 * Can cua gio Chinh Ty (00:00) cua ngay voi JDN nay
\r
349 function getCanHour0(jdn) {
\r
350 return CAN[(jdn-1)*2 % 10];
\r
353 function getCanChi(lunar) {
\r
354 var dayName, monthName, yearName;
\r
355 dayName = CAN[(lunar.jd + 9) % 10] + " " + CHI[(lunar.jd+1)%12];
\r
356 monthName = CAN[(lunar.year*12+lunar.month+3) % 10] + " " + CHI[(lunar.month+1)%12];
\r
357 if (lunar.leap == 1) {
\r
358 monthName += " (N)";
\r
360 yearName = getYearCanChi(lunar.year);
\r
361 return new Array(dayName, monthName, yearName);
\r
364 function getDayString(lunar, solarDay, solarMonth, solarYear) {
\r
366 var dayOfWeek = TUAN[(lunar.jd + 1) % 7];
\r
367 s = dayOfWeek + " " + solarDay + "/" + solarMonth + "/" + solarYear;
\r
369 s = s + "Ng\u00E0y " + lunar.day+" th\341ng "+lunar.month;
\r
370 if (lunar.leap == 1) {
\r
371 s = s + " nhu\u1EADn";
\r
376 function getTodayString() {
\r
377 var s = getDayString(currentLunarDate, today.getDate(), today.getMonth()+1, today.getFullYear());
\r
378 s += " n\u0103m " + getYearCanChi(currentLunarDate.year);
\r
382 function getCurrentTime() {
\r
383 today = new Date();
\r
384 var Std = today.getHours();
\r
385 var Min = today.getMinutes();
\r
386 var Sec = today.getSeconds();
\r
387 var s1 = ((Std < 10) ? "0" + Std : Std);
\r
388 var s2 = ((Min < 10) ? "0" + Min : Min);
\r
389 //var s3 = ((Sec < 10) ? "0" + Sec : Sec);
\r
390 //return s1 + ":" + s2 + ":" + s3;
\r
391 return s1 + ":" + s2;
\r
394 function getGioHoangDao(jd) {
\r
395 var chiOfDay = (jd+1) % 12;
\r
396 var gioHD = GIO_HD[chiOfDay % 6]; // same values for Ty' (1) and Ngo. (6), for Suu and Mui etc.
\r
399 for (var i = 0; i < 12; i++) {
\r
400 if (gioHD.charAt(i) == '1') {
\r
402 ret += ' ('+(i*2+23)%24+'h-'+(i*2+1)%24+'h)';
\r
403 if (count++ < 5) ret += ', ';
\r
404 if (count == 3) ret += '<br>';
\r
410 function getTHU(jd){
\r
411 return TUAN[(jd+1)%7];
\r
414 function getTHUINT(jd){
\r