Chia sẻ  [C#] Chuyển đổi dương lịch sang âm lịch

lvt491
Mình sưu tầm được trên mạng nhé. Bạn nào học lập trình biết đâu cần đến.
Cụ thể code này là nhập vào 1 ngày tháng năm dương lịch cụ thể sẽ được kết quả ngày tháng năm âm lịch tương ứng.

AL.jpg


C#:
    class ClassAL
    {
        enum Can { Giáp, Ất, Bính, Đinh, Mậu, Kỷ, Canh, Tân, Nhâm, Quý }
        enum Chi { Tý, Sửu, Dần, Mão, Thìn, Tỵ, Ngọ, Mùi, Thân, Dậu, Tuất, Hợi }

        public string CanChiNam(int yy)
        {
            return (Can)((yy + 6) % 10) + " " + (Chi)((yy + 8) % 12) + " (" + yy + ")";
            //Trả về kết quả vd: Tân Mùi (1991)
        }

        public string CanChiThang(int mm, int yy) //mm, yy = tháng, năm âm lịch
        {
            return (Can)((yy * 12 + mm + 3) % 10) + " " + (Chi)((mm + 1) % 12);
        }

        public int INT(double d)
        {
            return (int)Math.Floor(d);
        }

        public int MOD(int x, int y)
        {
            int z = x - (int)(y * Math.Floor(((double)x / y)));
            if (z == 0)
            {
                z = y;
            }
            return z;
        }

        //Đổi ngày dương lịch ra số ngày Julius
        public double SolarToJD(int D, int M, int Y)
        {
            double JD;
            if (Y > 1582 || (Y == 1582 && M > 10) || (Y == 1582 && M == 10 && D > 14))
            {
                JD = 367 * Y - INT(7 * (Y + INT((M + 9) / 12)) / 4) - INT(3 * (INT((Y + (M - 9) / 7) / 100) + 1) / 4) + INT(275 * M / 9) + D + 1721028.5;
            }
            else
            {
                JD = 367 * Y - INT(7 * (Y + 5001 + INT((M - 9) / 7)) / 4) + INT(275 * M / 9) + D + 1729776.5;
            }
            return JD;
        }

        //Đổi số ngày Julius ra ngày dương lịch
        public int[] SolarFromJD(double JD)
        {
            int Z, A, alpha, B, C, D, E, dd, mm, yyyy;
            double F;
            Z = INT(JD + 0.5);
            F = (JD + 0.5) - Z;
            if (Z < 2299161)
            {
                A = Z;
            }
            else
            {
                alpha = INT((Z - 1867216.25) / 36524.25);
                A = Z + 1 + alpha - INT(alpha / 4);
            }
            B = A + 1524;
            C = INT((B - 122.1) / 365.25);
            D = INT(365.25 * C);
            E = INT((B - D) / 30.6001);
            dd = INT(B - D - INT(30.6001 * E) + F);
            if (E < 14)
            {
                mm = E - 1;
            }
            else
            {
                mm = E - 13;
            }
            if (mm < 3)
            {
                yyyy = C - 4715;
            }
            else
            {
                yyyy = C - 4716;
            }
            return new int[] { dd, mm, yyyy };
        }

        //Chuyển đổi số ngày Julius / ngày dương lịch theo giờ địa phương LOCAL_TIMEZONE, Việt Nam: LOCAL_TIMEZONE = 7.0
        public int[] LocalFromJD(double JD)
        {
            return SolarFromJD(JD + (7.0 / 24.0));
        }

        public double LocalToJD(int D, int M, int Y)
        {
            return SolarToJD(D, M, Y) - (7.0 / 24.0);
        }

        //Tính thời điểm Sóc
        public double NewMoon(int k)
        {
            double T = k / 1236.85;
            double T2 = T * T;
            double T3 = T2 * T;
            double dr = Math.PI / 180;
            double Jd1 = 2415020.75933 + 29.53058868 * k + 0.0001178 * T2 - 0.000000155 * T3;
            Jd1 = Jd1 + 0.00033 * Math.Sin((166.56 + 132.87 * T - 0.009173 * T2) * dr);
            double M = 359.2242 + 29.10535608 * k - 0.0000333 * T2 - 0.00000347 * T3;
            double Mpr = 306.0253 + 385.81691806 * k + 0.0107306 * T2 + 0.00001236 * T3;
            double F = 21.2964 + 390.67050646 * k - 0.0016528 * T2 - 0.00000239 * T3;
            double C1 = (0.1734 - 0.000393 * T) * Math.Sin(M * dr) + 0.0021 * Math.Sin(2 * dr * M);
            C1 = C1 - 0.4068 * Math.Sin(Mpr * dr) + 0.0161 * Math.Sin(dr * 2 * Mpr);
            C1 = C1 - 0.0004 * Math.Sin(dr * 3 * Mpr);
            C1 = C1 + 0.0104 * Math.Sin(dr * 2 * F) - 0.0051 * Math.Sin(dr * (M + Mpr));
            C1 = C1 - 0.0074 * Math.Sin(dr * (M - Mpr)) + 0.0004 * Math.Sin(dr * (2 * F + M));
            C1 = C1 - 0.0004 * Math.Sin(dr * (2 * F - M)) - 0.0006 * Math.Sin(dr * (2 * F + Mpr));
            C1 = C1 + 0.0010 * Math.Sin(dr * (2 * F - Mpr)) + 0.0005 * Math.Sin(dr * (2 * Mpr + M));
            double deltat;
            if (T < -11)
            {
                deltat = 0.001 + 0.000839 * T + 0.0002261 * T2 - 0.00000845 * T3 - 0.000000081 * T * T3;
            }
            else
            {
                deltat = -0.000278 + 0.000265 * T + 0.000262 * T2;
            };
            double JdNew = Jd1 + C1 - deltat;
            return JdNew;
        }

        //Tính vị trí của mặt trời
        public double SunLongitude(double jdn)
        {
            double T = (jdn - 2451545.0) / 36525;
            double T2 = T * T;
            double dr = Math.PI / 180;
            double M = 357.52910 + 35999.05030 * T - 0.0001559 * T2 - 0.00000048 * T * T2;
            double L0 = 280.46645 + 36000.76983 * T + 0.0003032 * T2;
            double DL = (1.914600 - 0.004817 * T - 0.000014 * T2) * Math.Sin(dr * M);
            DL = DL + (0.019993 - 0.000101 * T) * Math.Sin(dr * 2 * M) + 0.000290 * Math.Sin(dr * 3 * M);
            double L = L0 + DL;
            L = L * dr;
            L = L - Math.PI * 2 * (INT(L / (Math.PI * 2)));
            return L;
        }

        //Tính tháng âm lịch chứa ngày Đông chí
        public int[] LunarMonth11(int Y)
        {
            double off = LocalToJD(31, 12, Y) - 2415021.076998695;
            int k = INT(off / 29.530588853);
            double jd = NewMoon(k);
            int[] ret = LocalFromJD(jd);
            double sunLong = SunLongitude(LocalToJD(ret[0], ret[1], ret[2]));
            if (sunLong > 3 * Math.PI / 2)
            {
                jd = NewMoon(k - 1);
            }
            return LocalFromJD(jd);
        }

        //Tính năm âm lịch
        public int[][] LunarYear(int Y)
        {
            int[][] ret = null;
            int[] month11A = LunarMonth11(Y - 1);
            double jdMonth11A = LocalToJD(month11A[0], month11A[1], month11A[2]);
            int k = (int)Math.Floor(0.5 + (jdMonth11A - 2415021.076998695) / 29.530588853);
            int[] month11B = LunarMonth11(Y);
            double off = LocalToJD(month11B[0], month11B[1], month11B[2]) - jdMonth11A;
            bool leap = off > 365.0;
            if (!leap)
            {
                ret = new int[13][];
            }
            else
            {
                ret = new int[14][];
            }
            ret[0] = new int[] { month11A[0], month11A[1], month11A[2], 0, 0 };
            ret[ret.Length - 1] = new int[] { month11B[0], month11B[1], month11B[2], 0, 0 };
            for (int i = 1; i < ret.Length - 1; i++)
            {
                double nm = NewMoon(k + i);
                int[] a = LocalFromJD(nm);
                ret[i] = new int[] { a[0], a[1], a[2], 0, 0 };
            }
            for (int i = 0; i < ret.Length; i++)
            {
                ret[i][3] = MOD(i + 11, 12);
            }
            if (leap)
            {
                initLeapYear(ret);
            }
            return ret;
        }

        //Tính tháng nhuận
        public void initLeapYear(int[][] ret)
        {
            double[] sunLongitudes = new double[ret.Length];
            for (int i = 0; i < ret.Length; i++)
            {
                int[] a = ret[i];
                double jdAtMonthBegin = LocalToJD(a[0], a[1], a[2]);
                sunLongitudes[i] = SunLongitude(jdAtMonthBegin);
            }
            bool found = false;
            for (int i = 0; i < ret.Length; i++)
            {
                if (found)
                {
                    ret[i][3] = MOD(i + 10, 12);
                    continue;
                }
                double sl1 = sunLongitudes[i];
                double sl2 = sunLongitudes[i + 1];
                bool hasMajorTerm = Math.Floor(sl1 / Math.PI * 6) != Math.Floor(sl2 / Math.PI * 6);
                if (!hasMajorTerm)
                {
                    found = true;
                    ret[i][4] = 1;
                    ret[i][3] = MOD(i + 10, 12);
                }
            }
        }

        //Đổi ngày dương lịch ra âm lịch
        public int[] Solar2Lunar(int D, int M, int Y)
        {
            int yy = Y;
            int[][] ly = LunarYear(Y);
            int[] month11 = ly[ly.Length - 1];
            double jdToday = LocalToJD(D, M, Y);
            double jdMonth11 = LocalToJD(month11[0], month11[1], month11[2]);
            if (jdToday >= jdMonth11)
            {
                ly = LunarYear(Y + 1);
                yy = Y + 1;
            }
            int i = ly.Length - 1;
            while (jdToday < LocalToJD(ly[i][0], ly[i][1], ly[i][2]))
            {
                i--;
            }
            int dd = (int)(jdToday - LocalToJD(ly[i][0], ly[i][1], ly[i][2])) + 1;
            int mm = ly[i][3];
            if (mm >= 11)
            {
                yy--;
            }
            return new int[] { dd, mm, yy, ly[i][4] };
            //Nếu ly[i][4] == 1 => tháng mm Nhuận
        }
    }
 
Sửa lần cuối:
Trả lời

babylon88

Búa Gỗ Đôi
Câu chuyện How to ...? Ra đoạn code ! Thực chất là phải quy câu Hỏi về bản chất Toán Học ! Vd : Tính Can = (Năm hiện tại + 6 )chia 10 dư bao nhiêu so với mảng để lấy giá trị ! Nên chung quy là từ quy luật Toán Học để suy ra bản chất câu trả lời ! Phần còn lại là diễn giải theo mã code ! Bác nào chuyên code thì biết thôi còn dân ngoại đạo cứ như phương trình tiếng Anh vậy
 

Nuti9696

Búa Gỗ
có ai lập được đổi từ giờ, ngày sang can, chi, ngũ hành không :v
 

temp0x

Búa Gỗ Đôi
cái này chắc dùng luôn thôi chứ cũng chịu, nàm thao mà biết được cách tính và quy luật tính của các cụ thời xa xưa.