Thuật toán tính âm lịch Việt Nam không phải một công thức đơn giản, mà là một chuỗi bước dựa trên thiên văn: tìm các thời điểm Sóc và Đông chí theo giờ Việt Nam, xác định tháng 11, kiểm tra năm có tháng nhuận hay không, rồi đánh số các tháng. Có thể hiểu gọn là lịch âm được "đo" từ bầu trời chứ không được "chia đều" như dương lịch.

Bài này viết cho cả người đọc muốn hiểu nguyên lý lẫn lập trình viên muốn tự cài đặt. Nguyên lý được giải thích bằng một ví dụ cụ thể. Phần kỹ thuật có bộ dữ liệu kiểm thử và đoạn mã mẫu đã được chạy thử. Chúng tôi cũng so sánh ba cách tính độc lập để trả lời một câu hỏi thực tế: các thuật toán âm lịch khác nhau ở đâu và mức độ ra sao? Nếu bạn cần phần nền tảng, hãy đọc trước bài Lịch Âm Dương Việt Nam: Nguyên lý, lịch sử và cách tính.

Vì sao không thể tính âm lịch bằng cách chia đều 29,53 ngày?

Đây là cách làm mà nhiều người nghĩ đến đầu tiên: lấy một ngày mùng 1 đã biết rồi cộng dần 29,53 ngày. Nhưng tháng trăng thực tế không đều, vì quỹ đạo Mặt Trăng và Trái Đất đều không tròn. Tính cho giai đoạn 1900–2100, độ dài tháng thay đổi từ 29,27 đến 29,83 ngày, và thời điểm Sóc thực có thể lệch khỏi thời điểm trung bình tới khoảng 14 giờ.

Chúng tôi đã thử cách cộng đều này trên 2.488 tháng. Kết quả là cách này cho sai ngày mùng 1 ở 36% số tháng, và kể cả khi đã căn chỉnh mốc cho tốt nhất thì vẫn sai 28%. Đó là lý do mọi thuật toán nghiêm túc đều phải tính vị trí thật của Mặt Trăng và Mặt Trời.

Năm bước đổi dương lịch sang âm lịch

Hãy theo dõi các bước qua một ví dụ: đổi ngày 5/11/2026 sang âm lịch.

  1. Tìm hai ngày Đông chí bao quanh ngày cần đổi. Với ví dụ này là 21/12/2025 và 22/12/2026, theo giờ Việt Nam.
  2. Tìm hai tháng 11. Tháng 11 là tháng chứa Đông chí, nên nó bắt đầu từ ngày Sóc cuối cùng không muộn hơn Đông chí. Ở đây là 20/12/2025 và 9/12/2026.
  3. Liệt kê các ngày Sóc giữa hai mốc đó. Mỗi ngày Sóc là một ngày mùng 1: 20/12, 19/1, 17/2, 19/3, 17/4, 17/5, 15/6, 14/7, 13/8, 11/9, 10/10, 9/11.
  4. Kiểm tra tháng nhuận. Giữa hai tháng 11 có 12 tháng nên năm này không nhuận. Nếu có 13 tháng, tháng nhuận sẽ là tháng đầu tiên không chứa trung khí. Bạn có thể xem cách làm trong bài Tháng nhuận âm lịch là gì?
  5. Đánh số tháng và đổi ngày. Bắt đầu từ tháng 11, các tháng lần lượt là 11, 12, 1, 2 và tiếp tục. Tháng bắt đầu từ 10/10/2026 là tháng 9. Ngày 5/11 cách 10/10 là 26 ngày, nên kết quả là ngày 27 tháng 9 âm lịch.

Về nguyên tắc chỉ có vậy. Phần khó nằm ở chỗ tính chính xác thời điểm Sóc và vị trí Mặt Trời, và luôn phải quy về giờ Việt Nam trước khi lấy ra ngày.

Thời điểm Sóc được tính thế nào?

Có hai hướng chính. Hướng thứ nhất dùng công thức thiên văn rút gọn: lấy thời điểm Sóc trung bình rồi cộng thêm các số hạng hiệu chỉnh theo vị trí Mặt Trời và Mặt Trăng. Thuật toán của Hồ Ngọc Đức, được cộng đồng lập trình Việt Nam dùng rộng rãi, đi theo hướng này. Ưu điểm của nó là rất gọn và không cần thư viện ngoài. Hướng thứ hai dùng thư viện thiên văn chính xác hơn, đổi lại phần cài đặt nặng hơn.

Câu hỏi thực tế là hai hướng này chênh nhau bao nhiêu. Chúng tôi đã tính 2.488 thời điểm Sóc từ 1900 đến 2100 bằng ba phương pháp độc lập, lấy thư viện ephem làm mốc so sánh:

Phương pháp Chênh lệch trung bình Chênh lệch lớn nhất
Astronomy Engine 0,7 phút 1,2 phút
Thuật toán Hồ Ngọc Đức 1,1 phút 3,9 phút

Chênh lệch chỉ khoảng một phút, và không có nghĩa bên nào đúng tuyệt đối. Nhưng lịch chỉ quan tâm Sóc thuộc ngày nào, nên một phút thường không ảnh hưởng gì. Trong giai đoạn 1968–2099, thuật toán Hồ Ngọc Đức và cách tính dùng ephem cho kết quả giống nhau ở 1.630 trên 1.632 tháng, kể cả tháng nhuận. Đây là một xác nhận rất tốt cho độ tin cậy của thuật toán này.

Ba tháng tương lai mà các thuật toán không thống nhất

Sai lệch chỉ xảy ra khi Sóc rơi sát nửa đêm. Trong giai đoạn trên, ba phương pháp không thống nhất ở ba tháng sau:

Thời điểm Sóc (giờ Việt Nam) Theo ephem Theo Hồ Ngọc Đức Theo Astronomy Engine
Tháng 12/2072, khoảng 23:58 9/12 10/12 9/12
Tháng 11/2077, khoảng 23:59 15/11 16/11 16/11
Tháng 10/2085, khoảng 23:59 18/10 18/10 19/10

Nói cách khác, với những tháng này, không thuật toán nào có thể khẳng định chắc chắn. Càng xa hiện tại, sai số càng lớn do vận tốc quay của Trái Đất không dự báo chính xác được. Các tháng này còn cách chúng ta khá xa, nên không ảnh hưởng đến việc dùng lịch hiện nay. Đây là lý do vì sao không có cuốn lịch nào thực sự "vạn niên", như chúng tôi đã phân tích ở bài Lịch vạn niên có đáng tin không?

Bộ dữ liệu kiểm thử cho lập trình viên

Nếu bạn tự cài đặt hoặc chọn một thư viện âm lịch, hãy thử với các ngày dưới đây. Chúng được chọn vì đều là những trường hợp dễ sai.

Dương lịch Âm lịch đúng Phát hiện lỗi gì
17/2/2007 1/1 Dùng giờ Trung Quốc sẽ ra 30/12
2/2/2030 1/1 Dùng giờ Trung Quốc sẽ ra 30/12
18/2/2053 1/1 Dùng giờ Trung Quốc sẽ ra 30/12
21/1/1985 1/1 Năm Tết lệch một tháng do Đông chí
21/3/1985 1/2 nhuận Tháng nhuận khác Trung Quốc
25/7/2025 1/6 nhuận Nhận diện tháng nhuận gần đây
23/6/2028 1/5 nhuận Nhận diện tháng nhuận sắp tới
21/4/2031 1/3 nhuận Sóc lúc 23:56, kiểm tra biên ngày
23/9/2033 1/9 Tháng không trung khí nhưng không nhuận
22/12/2033 1/11 nhuận Trường hợp nhuận tháng 11 hiếm gặp
20/1/2034 1/12 Tháng ngay sau nhuận tháng 11
26/9/2034 15/8 Trung thu lệch với giờ Trung Quốc

Những lỗi thường gặp khi cài đặt thuật toán âm lịch

  • Dùng sai múi giờ. Đây là lỗi phổ biến nhất. Nếu lấy thư viện âm lịch Trung Quốc, các ngày lệch sẽ sai âm thầm, vì phần lớn thời gian kết quả vẫn trùng. Bài Vì sao Tết Việt Nam có năm không trùng Tết Trung Quốc? có danh sách các ngày này.
  • Quy đổi múi giờ sai thứ tự. Phải đổi thời điểm Sóc sang giờ Việt Nam rồi mới lấy ngày, không được làm tròn ngày theo UTC trước.
  • Coi mọi tháng thiếu trung khí là tháng nhuận. Trường hợp 23/9/2033 trong bảng trên cho thấy cách này sẽ sai, vì phải đếm đủ 13 tháng trước.
  • Quên xử lý tháng nhuận khi đánh số. Tháng nhuận mang số của tháng trước nó, nhiều chương trình lại đánh số tiếp.
  • Áp công thức hiện đại cho năm trước 1968. Kết quả có thể khác lịch đã dùng ở thời điểm đó, nhất là với miền Nam trước năm 1975.
  • Lẫn lộn tháng âm và tháng tiết khí. Khi tính Can Chi hay Tứ Trụ, cần xác định rõ đang dùng loại tháng nào.

Mã mẫu Python để đổi dương lịch sang âm lịch

Đoạn mã dưới đây thực hiện đúng năm bước đã nêu, dùng thư viện ephem nên ngắn gọn và dễ đọc. Cài đặt bằng lệnh pip install ephem. Mã được ưu tiên dễ hiểu, không tối ưu về tốc độ, nên nếu dùng trong sản phẩm bạn cần thêm bộ nhớ đệm theo năm.

import math
from datetime import date, timedelta
import ephem

TZ = 7  # Giờ Việt Nam

def local_day(t):
    return (ephem.Date(t).datetime() + timedelta(hours=TZ)).date()

def term(d):
    # Số thứ tự cung 30 độ của Mặt Trời lúc 0h ngày d (giờ địa phương)
    t = ephem.Date(f"{d.year}/{d.month}/{d.day}") - TZ / 24
    s = ephem.Sun(t)
    return int(math.degrees(ephem.Ecliptic(s, epoch=t).lon) // 30)

def month_11(year):
    # Ngày bắt đầu tháng chứa Đông chí của năm dương lịch year
    solstice = local_day(ephem.next_solstice(f"{year}/12/1"))
    t, last = ephem.Date(f"{year}/10/15"), None
    while True:
        t = ephem.next_new_moon(t)
        d = local_day(t)
        if d > solstice:
            return last
        last, t = d, ephem.Date(t + 1)

def lunar_months(year):
    # Các tháng từ tháng 11 năm year đến hết tháng 10 năm sau
    start, end = month_11(year), month_11(year + 1)
    days = [start]
    t = ephem.Date(f"{start.year}/{start.month}/{start.day}") + 1
    while days[-1] < end:
        t = ephem.next_new_moon(t)
        days.append(local_day(t))
        t = ephem.Date(t + 1)
    leap = None
    if len(days) - 1 == 13:
        for i in range(1, 13):
            if term(days[i]) == term(days[i + 1]):
                leap = i
                break
    months, num = [], 10
    for i, d in enumerate(days[:-1]):
        if i == leap:
            months.append((d, num, True))
        else:
            num = num % 12 + 1
            months.append((d, num, False))
    return months

def solar_to_lunar(d):
    # Trả về (ngày âm, tháng âm, có phải tháng nhuận hay không)
    for y in (d.year, d.year - 1):
        months = lunar_months(y)
        if months[0][0] <= d:
            for s, m, leap in reversed(months):
                if s <= d:
                    return (d - s).days + 1, m, leap

print(solar_to_lunar(date(2026, 11, 5)))  # (27, 9, False)

Chúng tôi đã chạy mã này cho toàn bộ giai đoạn 1968–2099 và đối chiếu với một bản lịch dựng riêng: 1.632 tháng đều khớp. Tất cả 12 ngày trong bộ kiểm thử trên cũng cho kết quả đúng. Lưu ý rằng hai bản này cùng dựa trên ephem, nên phép so sánh độc lập thực sự là với thuật toán Hồ Ngọc Đức đã nêu ở trên.

Câu hỏi thường gặp về thuật toán âm lịch

Có công thức nào đổi dương lịch sang âm lịch chỉ bằng một dòng không?

Không có công thức ngắn cho ngày âm chính xác, vì độ dài tháng phụ thuộc vị trí thực của Mặt Trăng và Mặt Trời. Một số app dùng bảng dữ liệu tính sẵn để tra nhanh, nhưng dữ liệu đó vẫn phải được tính bằng thuật toán.

Có thể tính âm lịch trong Excel không?

Khó. Excel phù hợp hơn với Can Chi của ngày, vốn chỉ là phép đếm. Với ngày âm, nên dùng thư viện hoặc bảng tra đã tính sẵn.

Thuật toán Hồ Ngọc Đức có chính xác không?

Có, ở mức đủ tốt cho lịch. So với ephem, chênh lệch trung bình khoảng 1 phút và giống nhau ở 1.630 trên 1.632 tháng trong giai đoạn 1968–2099.

Thuật toán âm lịch có dùng cho năm xa trong tương lai được không?

Được nhưng độ tin cậy giảm dần, đặc biệt ở những tháng có Sóc sát nửa đêm.

Lịch Việt Nam và lịch Trung Quốc dùng chung thuật toán không?

Dùng chung quy tắc, chỉ khác múi giờ. Chỉ cần đổi hằng số múi giờ trong mã mẫu là có thể tính theo giờ khác.

Đọc thêm trong chùm bài về lịch âm dương

Bạn có thể đọc bài trụ Lịch Âm Dương Việt Nam: Nguyên lý, lịch sử và cách tính, bài Tháng nhuận âm lịch là gì?, bài Can Chi là gì? và bài Lịch vạn niên có đáng tin không?

Phương pháp so sánh và nguồn tham khảo

Thời điểm Sóc từ 1900 đến 2100 được tính bằng ba cách: thư viện ephem, thư viện Astronomy Engine và bản cài đặt lại thuật toán Hồ Ngọc Đức bằng Python. Việc lấy ephem làm mốc chỉ để so sánh, không có nghĩa ephem là chuẩn tuyệt đối. Các kết quả tương lai là tính toán theo quy tắc hiện hành, không phải lịch đã ban hành.

Bài viết được biên soạn với sự hỗ trợ của AI, theo định hướng và hậu kiểm của ban biên tập Reviews365. Nếu phát hiện sai sót, xin hãy phản hồi để chúng tôi tính lại.

Theo Reviews365 tổng hợp và tính toán ()