Home Send email Guestbook

Thuật toán tính âm lịch

Hồ Ngọc Đức

Bài viết sau giới thiệu cách tính âm lịch Việt Nam và mô tả một số thuật toán dùng để chuyển đổi giữa ngày dương lịch và ngày âm lịch. Các thuật toán mô tả ở đây đã được đơn giản hóa nhiều để bạn đọc tiện theo dõi và dễ dàng sử dụng vào việc lập trình, do đó độ chính xác của chúng thấp hơn độ chính xác của chương trình âm lịch trực tuyến tại http://www.informatik.uni-leipzig.de/~duc/amlich/.

[If you cannot read Vietnamese: Old version in English]

Quy luật của âm lịch Việt Nam

Âm lịch Việt Nam là một loại lịch thiên văn. Nó được tính toán dựa trên sự chuyển động của mặt trời, trái đất và mặt trăng. Ngày tháng âm lịch được tính dựa theo các nguyên tắc sau:
  1. Ngày đầu tiên của tháng âm lịch là ngày chứa điểm Sóc
  2. Một năm bình thường có 12 tháng âm lịch, một năm nhuận có 13 tháng âm lịch
  3. Đông chí luôn rơi vào tháng 11 âm lịch
  4. Trong một năm nhuận, nếu có 1 tháng không có Trung khí thì tháng đó là tháng nhuận. Nếu nhiều tháng trong năm nhuận đều không có Trung khí thì chỉ tháng đầu tiên sau Đông chí là tháng nhuận
  5. Việc tính toán dựa trên kinh tuyến 105° đông.

Sóc là thời điểm hội diện, đó là khi trái đất, mặt trăng và mặt trời nằm trên một đường thẳng và mặt trăng nằm giữa trái đất và mặt trời. (Như thế góc giữa mặt trăng và mặt trời bằng 0 độ). Gọi là "hội diện" vì mặt trăng và mặt trời ở cùng một hướng đối với trái đất. Chu kỳ của điểm Sóc là khoảng 29,5 ngày. Ngày chứa điểm Sóc được gọi là ngày Sóc, và đó là ngày bắt đầu tháng âm lịch.

Trung khí là các điểm chia đường hoàng đạo thành 12 phần bằng nhau. Trong đó, bốn Trung khí giữa bốn mùa là đặc biệt nhất: Xuân phân (khoảng 20/3), Hạ chí (khoảng 22/6), Thu phân (khoảng 23/9) và Đông chí (khoảng 22/12).

Bởi vì dựa trên cả mặt trời và mặt trăng nên lịch Việt Nam không phải là thuần âm lịch mà là âm-dương-lịch. Theo các nguyên tắc trên, để tính ngày tháng âm lịch cho một năm bất kỳ chúng ta cần xác định những ngày nào trong năm chứa các thời điểm Sóc (New moon) và các thời điểm Trung khí (Major solar term). Một khi bạn đã tính được ngày Sóc, bạn đã biết được ngày bắt đầu và kết thúc của một tháng âm lịch: ngày mùng một của tháng âm lịch là ngày chứa điểm sóc.

Sau khi đã biết ngày bắt đầu/kết thúc các tháng âm lịch, bạn có thể xác định tên các tháng và tìm tháng nhuận theo cách sau. Đông chí luôn rơi vào tháng 11 của năm âm lịch. Bởi vậy chúng ta cần tính 2 điểm sóc: Sóc A ngay trước ngày Đông chí thứ nhất và Sóc B ngay trước ngày Đông chí thứ hai. Nếu khoảng cách giữa A và B là dưới 365 ngày thì năm âm lịch có 12 tháng, và những tháng đó có tên là: tháng 11, tháng 12, tháng 1, tháng 2, …, tháng 10. Ngược lại, nếu khoảng cách giữa hai sóc A và B là trên 365 ngày thì năm âm lịch này là năm nhuận, và chúng ta cần tìm xem đâu là tháng nhuận. Để làm việc này ta xem xét tất cả các tháng giữa A và B, tháng đầu tiên không chứa Trung khí sau ngày Đông chí thứ nhất là tháng nhuận. Tháng đó sẽ được mang tên của tháng trước nó kèm chữ "nhuận".

Khi tính ngày Sóc và ngày chứa Trung khí bạn cần lưu ý xem xét chính xác múi giờ. Đây là lý do tại sao có một vài điểm khác nhau giữa lịch Việt Nam và lịch Trung Quốc.Ví dụ, nếu bạn biết thời điểm hội diện là vào lúc yyyy-02-18 16:24:45 GMT thì ngày Sóc của lịch Việt Nam là 18 tháng 2, bởi vì 16:24:45 GMT là 23:24:45 cùng ngày, giờ Hà nội (GMT+7, kinh tuyến 105° đông). Tuy nhiên theo giờ Bắc Kinh (GMT+8, kinh tuyến 120° đông) thì Sóc là lúc 00:24:45 ngày yyyy-02-19, do đó tháng âm lịch của Trung Quốc lại bắt đầu ngày yyyy-02-19, chậm hơn lịch Việt Nam 1 ngày.

Ví dụ 1: Âm lịch năm 1984

Chúng ta áp dụng quy luật trên để tính âm lịch Việt nam năm 1984.

Ví dụ 2: Âm lịch năm 2004

Lập trình tính lịch âm

Đã có nhiều chương trình hoàn chỉnh phục vụ cho việc tính toán Sóc và Trung khí với tính chính xác cao. Tuy vậy, muốn tính càng chính xác thì thuật toán càng phức tạp. Muốn viết một chương trình âm lịch với độ chính xác cao bạn nên sử dụng một thư viện thiên văn có sẵn chứ không nên lập trình từ đầu. Bạn có thể tải mã nguồn mở (C, C++, Java...) hoặc DLL để tính các thông số trên tại nhiều trang, chẳng hạn http://www.projectpluto.com. Nếu bạn muốn tự lập trình thì có thể sử dụng những thuật toán sau đây. Chúng có lợi thế là tương đối đơn giản hơn nhưng vẫn cho kết quả khá tốt. (Sai số khi tính điểm Sóc vào khoảng từ 0 đến 15 phút).

Một số công thức hỗ trợ

Để tiện cho việc tính toán chúng ta sử dụng 2 hàm hỗ trợ để tính số ngày đã trôi qua kể từ một điểm gốc qui ước và ngược lại. Trong tính toán thiên văn người ta thường lấy ngày 1/1/4713 trước công nguyên của lịch Julius (tức ngày 24/11/4714 trước CN theo lịch Gregory) làm điểm gốc. Số ngày tính từ điểm gốc này gọi là ngày Julius của một ngày (Julian day number, gọi theo Julius Scaliger, người đề ra cách tính ngày này năm 1583) . Ví dụ, số ngày Julius của 1/1/2000 là 2451545.

Trong các công thức sau, phép chia a/b được hiểu như sau. Nếu cả a và b là số nguyên (int) thì / là chia số nguyên, bỏ phần dư. Ví dụ: 7 / 12 = 0; -5 / 12 = 0; -13 / 12 = -1. Nếu ít nhất một trong hai số là số thực (real, float, double) thì / là phép chia số thực, ví dụ: 7.25 / 2.4 = 3.0208333333333335. Chú ý: khi viết 7.0 ta hiểu là tính toán với số thực 7.0, còn nếu chỉ viết 7 sẽ tính với số nguyên 7.

Ngày dương lịch được tính theo lịch Gregory (Gregorian calendar), kể cả cho các năm trước 1582 khi lịch này được đưa vào sử dụng.

Đổi ngày dương lịch ra số ngày Julius

Viết ngày dương lịch dưới dạng d/m/y (ngày = d, tháng = m, năm = y). d là một số nguyên từ 1 đến 31, m từ 1 đến 12 và y là một số nguyên lớn hơn -4712 (âm 4712).

Gregorian2JD(int d, int m, int y)
1461 * ( y + 4800 + ( m - 14 ) / 12 ) / 4 +
( 367 * ( m - 2 - 12 * ( ( m - 14 ) / 12 ) ) ) / 12 -
( 3 * ( ( y + 4900 + ( m - 14 ) / 12 ) / 100 ) ) / 4 +
d - 32075

Đổi số ngày Julius ra ngày dương lịch

Cho jd là một số nguyên dương. Công thức sau đổi ngày Julius jd ra ngày dương lịch m/d/y:

JD2Gregorian(int jd)
l = jd + 68569;
n = ( 4 * l ) / 146097;
l = l - ( 146097 * n + 3 ) / 4;
i = ( 4000 * ( l + 1 ) ) / 1461001;
l = l - ( 1461 * i ) / 4 + 31;
j = ( 80 * l ) / 2447;
d = l - ( 2447 * j ) / 80;
l = j / 11;
m = j + 2 - ( 12 * l );
y = 100 * ( n - 49 ) + i + l;

Giải phương trình Kepler

Để tính vị trí thực của một vật thể quay trên một quĩ đạo hình ê-líp với độ lệch tâm ecc và vị trí trung bình mean, ta cần giải phương trình Kepler. Trong các thuật toán sau, PI = 3.14159265358979323846, sqrt(x) là căn bậc hai của x, abs(x) là giá trị tuyệt đối của x, floor(x) là số nguyên lớn nhất không lớn hơn x, còn sin, cos, tan, atan và atan2 là các hàm lượng giác quen thuộc.

kepler(double mean, double ecc)
double delta;
double E = mean;
do {
	delta = E - ecc * sin(E) - mean;
	E = E - delta / (1 - ecc * cos(E));
} while (abs(delta) > 0.0001);
return 2.0 * atan(tan(E / 2) * sqrt((1 + ecc) / (1 - ecc)));

Tính vị trí mặt trời tại một thời điểm

Thuật toán sau cho phép tính vị trí của mặt trời trên quĩ đạo của nó vào lúc 0h sáng ngày d/m/y dương lịch tại múi giờ tz. (tz là khoảng cách tính bằng giờ giữa giờ địa phương và giờ GMT.) Giờ Việt Nam trước GMT 7h, như thế tz = 7.0. Tại Nhật Bản lấy tz = 9.0, còn tại California lấy tz = -8.0. Kết quả mà thuật toán trả lại là một góc Rađian giữa 0 và 2*PI. Vị trí mặt trời được sử dụng để chia năm thời tiết thành 24 Khí (12 Tiết khí và 12 Trung khí). Một Trung khí là thời điểm mà kinh độ mặt trời có một trong những giá trị sau: 0*PI/6, 1*PI/6, 2*PI/6, 3*PI/6, 4*PI/6, 5*PI/6, 6*PI/6, 7*PI/6, 8*PI/6, 9*PI/6, 10*PI/6, 11*PI/6. Các điểm "Phân-Chí" được định nghĩa bằng các tọa độ sau: Xuân phân: 0, Hạ chí: PI/2, Thu phân: PI, Đông chí: 3*PI/2.

Trong các công thức sau, fixAngle là hàm dùng để chuẩn hoá một góc Rađian về khoảng từ 0 đến 2*PI:

fixAngle(x) = x - PI*2*floor(x/(PI*2))
Ví dụ: fixAngle(7.5*PI) = 7.5*PI - 2*PI*3 = 1.5*PI

SunLongitude(int d, int m, int y, double tz)
int x = Gregorian2JD(d, m, y);
double x2 = x - 2447892 - tz / 24.0;
double z = fixAngle(PI * 2 * x2 / 365.242191);
double angle = fixAngle(z - 0.05873240627141918);
angle = kepler(angle, 0.016713) + 4.935239984568769;
return fixAngle(angle);

Tính tuổi trăng tại một thời điểm

Tuổi trăng được hiểu là góc giữa mặt trăng và mặt trời (nhìn từ trái đất) tại một thời điểm. Thuật toán sau tính tuổi trăng vào lúc 0h sáng ngày d/m/y dương lịch tại múi giờ tz. Kết quả của thuật toán là một góc Rađian giữa 0 và 2*PI. Ngày đầu tháng âm lịch là ngày chứa điểm hội diện (điểm Sóc), đó là thời điểm khi tuổi trăng bằng 0.

MoonAge(int d, int m, int y, double tz)
double sunLongitude = SunLongitude(d, m, y, tz);
int x = Gregorian2JD(d, m, y);
double day = x - 2447892 - tz / 24.0;
double meanLongitude = fixAngle(0.22997150421858628 * day + 5.556284436750021);
double meanAnomalyMoon = fixAngle(meanLongitude - 0.001944368345221015 * day - 0.6342598060246725);
double epochAngle = fixAngle(PI * 2 * day / 365.242191);
double meanAnomalySun = fixAngle(epochAngle - 0.05873240627141918);
double evection = 0.022233749341155764 * sin(2 * (meanLongitude - sunLongitude) - meanAnomalyMoon);
double annual = 0.003242821750205464 * sin(meanAnomalySun);
double a3 = 0.00645771823237902 * sin(meanAnomalySun);
meanAnomalyMoon = meanAnomalyMoon + evection - annual - a3;
double center = 0.10975677534091541 * sin(meanAnomalyMoon);
double a4 = 0.0037350045992678655 * sin(2 * meanAnomalyMoon);
double moonLongitude = meanLongitude + evection + center - annual + a4;
double variation = 0.011489502465878671 * sin(2 * (moonLongitude - sunLongitude));
moonLongitude = moonLongitude + variation;
double nodeLongitude = fixAngle(5.559050068029439 - 0.0009242199067718253 * day);
nodeLongitude = nodeLongitude - 0.0027925268031909274 * sin(meanAnomalySun);
double y2 = sin(moonLongitude - nodeLongitude);
double x2 = cos(moonLongitude - nodeLongitude);
double moonEclipLong = atan2(y2 * cos(0.08980357792017056), x2) + nodeLongitude;
double ret = fixAngle(moonEclipLong - sunLongitude);
return ret;

Đổi ngày dương lịch ra ngày âm lịch

Với các công thức và thuật toán hỗ trợ trên chúng ta bây giờ có thể đổi ngày dương lịch ra ngày âm lịch. Để cho tiện chúng ta đánh số năm âm lịch theo năm dương lịch: năm âm lịch yyyy là năm bắt đầu trong năm dương lịch yyyy. Như thế những ngày cuối cùng của năm âm lịch yyyy thật ra là nằm trong năm dương lịch yyyy+1.

Tính ngày đầu tháng âm lịch

Cho ngày dương lịch d/m/y và múi giờ tz, ta tính xem tháng âm lịch chứa ngày d/m/y bắt đầu vào ngày nào. Trước hết, tính tuổi trăng moonAge1 tại lúc 0h và moonAge2 lúc 24h ngày d/m/y. Nếu moonAge1 > moonAge2 thì d/m/y là ngày chứa Sóc, nếu không lùi lại cho tới khi nào moonAge1 > moonAge2. (moonAge1 > moonAge2 chỉ xảy ra khi moonAge1 xấp xỉ 2*PI và moonAge2 xấp xỉ 0, khi đó trong ngày có một thời điểm mà tuổi trăng bằng 0.)

NewMoonBefore(int d, int m, int y, double tz)
int jdn = Gregorian2JD(d, m, y);
do {
  (d1, m1, y1) = JD2Gregorian(jdn);
  (d2, m2, y2) = JD2Gregorian(jdn+1);
  double moonAge1 = MoonAge(d1, m1, y1, tz);
  double moonAge2 = MoonAge(d2, m2, y2, tz);
  jdn = jdn - 1;
} while (moonAge2 > moonAge1);
return (d1, m1, y1);
Chú ý: cách tính này không nhanh lắm, cần tối ưu hóa khi lập trình. Chẳng hạn, khi biết một ngày không phải là ngày Sóc thì không nên nhảy lùi từng ngày một và kiểm tra ngày ngay trước đó mà có thể đoán là ngày Sóc cách ngày hiện tại khoảng bao nhiêu ngày để lùi lại tới sát ngày dầu tháng. Mặt trăng cần khoảng 29.5 ngày để đi hết một vòng tròn (2*PI), như thế để đạt được tuổi trăng moonAge thì cần khoảng moonAge/(2*PI/29.5) ngày.

Khi biết (d1, m1, y1) là ngày Sóc ngay trước (d, m, y), ta tính được khoảng cách giữa 2 ngày này là Gregorian2JD(d, m, y) - Gregorian2JD(d1, m1, y1) như thế biết (d, m, y) là ngày mùng mấy âm lịch. Nếu hiệu số này là 0 thì (d, m, y) chính là ngày mùng 1 âm lịch, ngày chứa điểm Sóc.

Khi đã biết một ngày Sóc ta có thể tính ngày Sóc sau đó bằng cách áp dụng hàm NewMoonBefore vào ngày sau ngày Sóc đầu 31 ngày: sau 31 ngày chắc chắn đã sang một tuần trăng khác, và ngày bắt đầu tuần trăng đó được tính với NewMoonBefore.

Tính tháng âm lịch chứa ngày Đông chí

Đông chí của một năm y thường rơi vào khoảng ngày 20-22 tháng 12 năm đó. Chúng ta nhớ lại rằng Đông chí là thời điểm mà kinh độ của mặt trời trên đường hoàng đạo là 3*PI/2. Trước hết ta tính ngày (d1, m1, y1) bắt đầu tháng âm lịch chứa ngày 24/12 dương lịch bằng phương thức NewMoonBefore nói trên. Đông chí chỉ rơi vào tháng âm lịch bắt đầu ngày (d1, m1, y1) nếu kinh độ mặt trời vào lúc 0h ngày (d1, m1, y1) nhỏ hơn hoặc bằng 3*PI/2. Nếu không thì tháng âm lịch trước đó là tháng có Đông chí.

LunarMonth11(int y, double tz)
(d1, m1, y1) = NewMoonBefore(24, 12, y, tz);
double sunLong = SunLongitude(d1, m1, y1, tz);
if (sunLong > 3*PI/2) {
    (d1, m1, y1) = NewMoonBefore(26, 11, y, tz);
}
return (d1, m1, y1);

Kiểm tra xem tháng âm lịch có chứa Trung Khí hay không

Một tháng âm lịch có Trung khí nếu một trong các góc định nghĩa Trung khí (0*PI/6, PI/6, 2*PI/6, ..., 11*PI/6) nằm giữa kinh độ mặt trời (Sun Longitude) tại ngày đầu tháng và kinh độ mặt trời tại ngày đầu tháng sau đó. Chẳng hạn, tháng âm lịch chứa ngày (d,m,y) bắt đầu vào ngày (d1,m1,y1). Tháng âm lịch sau đó bắt đầu vào ngày (d2,m2,y2). Nếu trong khoảng [SunLongitude(d1,m1,y1,tz), SunLongitude(d2,m2,y2,tz)) có chứa một điểm định nghĩa Trung khí thì tháng âm lịch bắt đầu ngày (d1,m1,y1) có chứa Trung khí.

HasMajorSolarTerm(int d1, int m1, int y1, double tz)
(d2, m2, y2) = NewMoonBefore(JD2Gregorian(31 + Gregorian2JD(d1,m1,y1)));
double sl1 = SunLongitude(d1, m1, y1, tz);
double sl2 = SunLongitude(d2, m2, y2, tz);
return (0 IN [sl1, sl2]) OR (PI/6 IN [sl1, sl2]) OR ... OR (11*PI/6 IN [sl1, sl2])

Tính năm âm lịch

Để tiện cho việc tính toán ngày tháng ta định nghĩa một hàm MOD như sau:

MOD(int x, int y)
z = x - y*(x/y);
if (z == 0) {
  z = y;
}
return z;
Như thế MOD tính số dư của phép chia x/y với một khác biệt nhỏ: nếu số dư là 0 thì MOD trả lại kết quả là y.

Để đổi ngày d/m/y dương lịch ra âm lịch, trước hết ta sẽ chọn hai ngày SOC_A=(d11a, m11a, y11a) và SOC_B=(d11b, m11b, y11b) là những ngày bắt đầu 11 âm lịch của hai năm liền nhau sao cho d/m/y nằm giữa 2 ngày này. Hai ngày Sóc này có thể là LunarMonth11(y-1, tz), LunarMonth11(y, tz) hoặc LunarMonth11(y+1, tz). Như vậy ta cần xem d/m/y nằm trong khoảng [LunarMonth11(y-1, tz), LunarMonth11(y, tz)] hay trong khoảng [LunarMonth11(y, tz), LunarMonth11(y+1, tz)]. Các tháng âm lịch trong khoảng giữa 2 ngày này sẽ là cơ sở để đổi ngày d/m/y ra ngày âm lịch. Trong một năm thường ta sẽ có 12 tháng: [thang_11, thang_12, thang_1, ..., thang_10] và trong năm nhuận có 13 tháng: [thang_11, ..., thang_k, thang_k_nhuan, thang_k+1, ..., thang_10].

LunarYearContaining(int d, int m, int y, double tz)
if (LunarMonth11(y-1, tz) <e; (d, m, y) < LunarMonth11(y, tz) ) {
  (d11a, m11a, y11a) = LunarMonth11(y-1, tz);
  (d11b, m11b, y11b) = LunarMonth11(y, tz);
} else {
  (d11a, m11a, y11a) = LunarMonth11(y, tz);
  (d11b, m11b, y11b) = LunarMonth11(y+1, tz);
}
if (Gregorian2JD(d11b, m11b, y11b) - Gregorian2JD(d11a, m11a, y11a) < 365) {
  NamNhuan = false;
  thang_11 = (d11a, m11a, y11a);
  thang_12 = NewMoonBefore(JD2Gregorian(Gregorian2JD(thang11) + 31));
  thang_1 = NewMoonBefore(JD2Gregorian(Gregorian2JD(thang12) + 31));
  ...
  thang_10 = NewMoonBefore(JD2Gregorian(Gregorian2JD(thang9) + 31));
} else {
  NamNhuan = true;
  ThangNhuan = 0;
  mm_1 = (d11a, m11a, y11a);
  for (i = 1 TO 12) {
    k = i+1;
    mm_k = NewMoonBefore(JD2Gregorian(Gregorian2JD(mm_i) + 31));
    if (ThangNhuan == 0 AND NOT HasMajorSolarTerm(mm_k)) {
      ThangNhuan = k;
    }
  }
  k = ThangNhuan;
  for (i = 1 TO k-1) {
    j = MOD(i + 10, 12);
    thang_j = mm_i;
  }
  thang_k_nhuan = mm_k;
  for (i = k+1 TO 13) {
    j = MOD(i + 9, 12);
    thang_j = mm_i;
  }
}

Đổi ngày dương lịch ra âm lịch và ngược lại

Sau khi đã tính được tất cả các tháng âm lịch trong một năm ta có thể dễ dàng tìm ra tháng âm lịch chứa một ngày dương lịch d/m/y bất kỳ: đó là một tháng mà ngày đầu tháng (d1,m1,y1) sớm hơn hoặc bằng d/m/y và ngày đầu tháng sau đó (d2,m2,y2) muộn hơn d/m/y. Ngày d/m/y là ngày mùng (Gregorian2JD(d,m,y)-Gregorian2JD(d1,m1,y1)+1) âm lịch.

Ngược lại, khi biết ngày âm lịch ta sẽ tính xem ngày đầu tháng âm lịch đó là ngày bao nhiêu dương lịch, từ đó ta có thể tính được ngày dương lịch tương ứng.

Tính ngày thứ và Can-Chi cho ngày và tháng âm lịch

Ngày thứ lặp lại theo chu kỳ 7 ngày, như thế để biết một ngày d/m/y bất kỳ là thứ mấy ta chỉ việc tìm số dư của số ngày Julius của ngày này cho 7:
X=MOD(Gregorian2JD(d,m,y)+2, 7);
if (X == 1)  return Chu_Nhat;
if (X == 2) return Thu_2;
...
if (X == 7) return Thu_7;

Tương tự như vậy, hiệu Can-Chi của ngày cũng lặp lại theo chu kỳ 60 ngày, như thế nó cũng có thể tính được một cách đơn giản:

X=MOD(Gregorian2JD(d,m,y)+5, 10);
if (X == 1)  CAN = "Giap";
if (X == 2) CAN = "At";
...
if (X == 10) return "Quy";

Y=MOD(Gregorian2JD(d,m,y)+1, 12);
if (Y == 1)  CHI = "Ty";
if (X == 2) CHI = "Suu";
...
if (X == 12) CHI = "Hoi";

Trong một năm âm lịch, tháng 11 là tháng Tý, tháng 12 là Sửu, tháng Giêng là tháng Dần v.v. Can của tháng M năm Y âm lịch được tính theo công thức sau:

X=MOD(Y*12+M+4, 10);
if (X == 1)  CAN = "Giap";
if (X == 2) CAN = "At";
...
if (X == 10) return "Quy";
Ví dụ, Can-Chi của tháng 3 âm lịch năm Giáp Thân 2004 là Mậu Thìn: tháng 3 âm lịch là tháng Thìn, và MOD(2004*12+4+3, 10) = MOD(24055, 10) = 5, như vậy Can của tháng là Mậu.

Một tháng nhuận không có tên riêng mà lấy tên của tháng trước đó kèm thêm chữ "Nhuận", VD: tháng 2 nhuận năm Giáp Thân 2004 là tháng Đinh Mão nhuận.

Tài liệu tham khảo


Sửa đổi lần cuối: 09/07/2004