Advertisement
thieumao

Đổi lịch dương sang lịch âm

Jun 30th, 2016
37
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 9.21 KB | None | 0 0
  1. /**
  2. * @author duc
  3. *
  4. */
  5. public class VietCalendar {
  6.     public static final double PI = Math.PI;
  7.     /**
  8.      *
  9.      * @param dd
  10.      * @param mm
  11.      * @param yy
  12.      * @return the number of days since 1 January 4713 BC (Julian calendar)
  13.      */
  14.     public static int jdFromDate(int dd, int mm, int yy) {
  15.         int a = (14 - mm) / 12;
  16.         int y = yy+4800-a;
  17.         int m = mm+12*a-3;
  18.         int jd = dd + (153*m+2)/5 + 365*y + y/4 - y/100 + y/400 - 32045;
  19.         if (jd < 2299161) {
  20.             jd = dd + (153*m+2)/5 + 365*y + y/4 - 32083;
  21.         }
  22.         //jd = jd - 1721425;
  23.         return jd;
  24.     }
  25.     /**
  26.      * http://www.tondering.dk/claus/calendar.html
  27.      * Section: Is there a formula for calculating the Julian day number?
  28.      * @param jd - the number of days since 1 January 4713 BC (Julian calendar)
  29.      * @return
  30.      */
  31.     public static int[] jdToDate(int jd) {
  32.         int a, b, c;
  33.         if (jd > 2299160) { // After 5/10/1582, Gregorian calendar
  34.             a = jd + 32044;
  35.             b = (4*a+3)/146097;
  36.             c = a - (b*146097)/4;
  37.         } else {
  38.             b = 0;
  39.             c = jd + 32082;
  40.         }
  41.         int d = (4*c+3)/1461;
  42.         int e = c - (1461*d)/4;
  43.         int m = (5*e+2)/153;
  44.         int day = e - (153*m+2)/5 + 1;
  45.         int month = m + 3 - 12*(m/10);
  46.         int year = b*100 + d - 4800 + m/10;
  47.         return new int[]{day, month, year};
  48.     }
  49.     /**
  50.      * Solar longitude in degrees
  51.      * Algorithm from: Astronomical Algorithms, by Jean Meeus, 1998
  52.      * @param jdn - number of days since noon UTC on 1 January 4713 BC
  53.      * @return
  54.      */
  55.     public static double SunLongitude(double jdn) {
  56.         //return CC2K.sunLongitude(jdn);
  57.         return SunLongitudeAA98(jdn);
  58.     }
  59.     public static double SunLongitudeAA98(double jdn) {
  60.         double T = (jdn - 2451545.0 ) / 36525; // Time in Julian centuries from 2000-01-01 12:00:00 GMT
  61.         double T2 = T*T;
  62.         double dr = PI/180; // degree to radian
  63.         double M = 357.52910 + 35999.05030*T - 0.0001559*T2 - 0.00000048*T*T2; // mean anomaly, degree
  64.         double L0 = 280.46645 + 36000.76983*T + 0.0003032*T2; // mean longitude, degree
  65.         double DL = (1.914600 - 0.004817*T - 0.000014*T2)*Math.sin(dr*M);
  66.         DL = DL + (0.019993 - 0.000101*T)*Math.sin(dr*2*M) + 0.000290*Math.sin(dr*3*M);
  67.         double L = L0 + DL; // true longitude, degree
  68.         L = L - 360*(INT(L/360)); // Normalize to (0, 360)
  69.         return L;
  70.     }
  71.     public static double NewMoon(int k) {
  72.         //return CC2K.newMoonTime(k);
  73.         return NewMoonAA98(k);
  74.     }
  75.     /**
  76.      * Julian day number of the kth new moon after (or before) the New Moon of 1900-01-01 13:51 GMT.
  77.      * Accuracy: 2 minutes
  78.      * Algorithm from: Astronomical Algorithms, by Jean Meeus, 1998
  79.      * @param k
  80.      * @return the Julian date number (number of days since noon UTC on 1 January 4713 BC) of the New Moon
  81.      */
  82.  
  83.     public static double NewMoonAA98(int k) {
  84.         double T = k/1236.85; // Time in Julian centuries from 1900 January 0.5
  85.         double T2 = T * T;
  86.         double T3 = T2 * T;
  87.         double dr = PI/180;
  88.         double Jd1 = 2415020.75933 + 29.53058868*k + 0.0001178*T2 - 0.000000155*T3;
  89.         Jd1 = Jd1 + 0.00033*Math.sin((166.56 + 132.87*T - 0.009173*T2)*dr); // Mean new moon
  90.         double M = 359.2242 + 29.10535608*k - 0.0000333*T2 - 0.00000347*T3; // Sun's mean anomaly
  91.         double Mpr = 306.0253 + 385.81691806*k + 0.0107306*T2 + 0.00001236*T3; // Moon's mean anomaly
  92.         double F = 21.2964 + 390.67050646*k - 0.0016528*T2 - 0.00000239*T3; // Moon's argument of latitude
  93.         double C1=(0.1734 - 0.000393*T)*Math.sin(M*dr) + 0.0021*Math.sin(2*dr*M);
  94.         C1 = C1 - 0.4068*Math.sin(Mpr*dr) + 0.0161*Math.sin(dr*2*Mpr);
  95.         C1 = C1 - 0.0004*Math.sin(dr*3*Mpr);
  96.         C1 = C1 + 0.0104*Math.sin(dr*2*F) - 0.0051*Math.sin(dr*(M+Mpr));
  97.         C1 = C1 - 0.0074*Math.sin(dr*(M-Mpr)) + 0.0004*Math.sin(dr*(2*F+M));
  98.         C1 = C1 - 0.0004*Math.sin(dr*(2*F-M)) - 0.0006*Math.sin(dr*(2*F+Mpr));
  99.         C1 = C1 + 0.0010*Math.sin(dr*(2*F-Mpr)) + 0.0005*Math.sin(dr*(2*Mpr+M));
  100.         double deltat;
  101.         if (T < -11) {
  102.             deltat= 0.001 + 0.000839*T + 0.0002261*T2 - 0.00000845*T3 - 0.000000081*T*T3;
  103.         } else {
  104.             deltat= -0.000278 + 0.000265*T + 0.000262*T2;
  105.         };
  106.         double JdNew = Jd1 + C1 - deltat;
  107.         return JdNew;
  108.     }
  109.     public static int INT(double d) {
  110.         return (int)Math.floor(d);
  111.     }
  112.     public static double getSunLongitude(int dayNumber, double timeZone) {
  113.         return SunLongitude(dayNumber - 0.5 - timeZone/24);
  114.     }
  115.     public static int getNewMoonDay(int k, double timeZone) {
  116.         double jd = NewMoon(k);
  117.         return INT(jd + 0.5 + timeZone/24);
  118.     }
  119.     public static int getLunarMonth11(int yy, double timeZone) {
  120.         double off = jdFromDate(31, 12, yy) - 2415021.076998695;
  121.         int k = INT(off / 29.530588853);
  122.         int nm = getNewMoonDay(k, timeZone);
  123.         int sunLong = INT(getSunLongitude(nm, timeZone)/30);
  124.         if (sunLong >= 9) {
  125.             nm = getNewMoonDay(k-1, timeZone);
  126.         }
  127.         return nm;
  128.     }
  129.     public static int getLeapMonthOffset(int a11, double timeZone) {
  130.         int k = INT(0.5 + (a11 - 2415021.076998695) / 29.530588853);
  131.         int last; // Month 11 contains point of sun longutide 3*PI/2 (December solstice)
  132.         int i = 1; // We start with the month following lunar month 11
  133.         int arc = INT(getSunLongitude(getNewMoonDay(k+i, timeZone), timeZone)/30);
  134.         do {
  135.             last = arc;
  136.             i++;
  137.             arc = INT(getSunLongitude(getNewMoonDay(k+i, timeZone), timeZone)/30);
  138.         } while (arc != last && i < 14);
  139.         return i-1;
  140.     }
  141.     /**
  142.      *
  143.      * @param dd
  144.      * @param mm
  145.      * @param yy
  146.      * @param timeZone
  147.      * @return array of [lunarDay, lunarMonth, lunarYear, leapOrNot]
  148.      */
  149.     public static int[] convertSolar2Lunar(int dd, int mm, int yy, double timeZone) {
  150.         int lunarDay, lunarMonth, lunarYear, lunarLeap;
  151.         int dayNumber = jdFromDate(dd, mm, yy);
  152.         int k = INT((dayNumber - 2415021.076998695) / 29.530588853);
  153.         int monthStart = getNewMoonDay(k+1, timeZone);
  154.         if (monthStart > dayNumber) {
  155.             monthStart = getNewMoonDay(k, timeZone);
  156.         }
  157.         int a11 = getLunarMonth11(yy, timeZone);
  158.         int b11 = a11;
  159.         if (a11 >= monthStart) {
  160.             lunarYear = yy;
  161.             a11 = getLunarMonth11(yy-1, timeZone);
  162.         } else {
  163.             lunarYear = yy+1;
  164.             b11 = getLunarMonth11(yy+1, timeZone);
  165.         }
  166.         lunarDay = dayNumber-monthStart+1;
  167.         int diff = INT((monthStart - a11)/29);
  168.         lunarLeap = 0;
  169.         lunarMonth = diff+11;
  170.         if (b11 - a11 > 365) {
  171.             int leapMonthDiff = getLeapMonthOffset(a11, timeZone);
  172.             if (diff >= leapMonthDiff) {
  173.                 lunarMonth = diff + 10;
  174.                 if (diff == leapMonthDiff) {
  175.                     lunarLeap = 1;
  176.                 }
  177.             }
  178.         }
  179.         if (lunarMonth > 12) {
  180.             lunarMonth = lunarMonth - 12;
  181.         }
  182.         if (lunarMonth >= 11 && diff < 4) {
  183.             lunarYear -= 1;
  184.         }
  185.         return new int[]{lunarDay, lunarMonth, lunarYear, lunarLeap};
  186.     }
  187.     public static int[] convertLunar2Solar(int lunarDay, int lunarMonth, int lunarYear, int lunarLeap, double timeZone) {
  188.         int a11, b11;
  189.         if (lunarMonth < 11) {
  190.             a11 = getLunarMonth11(lunarYear-1, timeZone);
  191.             b11 = getLunarMonth11(lunarYear, timeZone);
  192.         } else {
  193.             a11 = getLunarMonth11(lunarYear, timeZone);
  194.             b11 = getLunarMonth11(lunarYear+1, timeZone);
  195.         }
  196.         int k = INT(0.5 + (a11 - 2415021.076998695) / 29.530588853);
  197.         int off = lunarMonth - 11;
  198.         if (off < 0) {
  199.             off += 12;
  200.         }
  201.         if (b11 - a11 > 365) {
  202.             int leapOff = getLeapMonthOffset(a11, timeZone);
  203.             int leapMonth = leapOff - 2;
  204.             if (leapMonth < 0) {
  205.                 leapMonth += 12;
  206.             }
  207.             if (lunarLeap != 0 && lunarMonth != leapMonth) {
  208.                 System.out.println("Invalid input!");
  209.                 return new int[]{0, 0, 0};
  210.             } else if (lunarLeap != 0 || off >= leapOff) {
  211.                 off += 1;
  212.             }
  213.         }
  214.         int monthStart = getNewMoonDay(k+off, timeZone);
  215.         return jdToDate(monthStart+lunarDay-1);
  216.     }
  217.  
  218.     public static void main(String[] args) {
  219.         double TZ = 7.0;
  220.         int start = jdFromDate(1, 1, 2001);
  221.         int step = 15;
  222.         int count = -1;
  223.         while (count++ < 240) {
  224.             int jd = start + step*count;
  225.             int[] s = jdToDate(jd);
  226.             int[] l = convertSolar2Lunar(s[0], s[1], s[2], TZ);
  227.             int[] s2 = convertLunar2Solar(l[0], l[1], l[2], l[3], TZ);
  228.             if (s[0] == s2[0] && s[1] == s2[1] && s[2] == s2[2]) {
  229.                 System.out.println("OK! "+s[0]+"/"+s[1]+"/"+s[2]+" -> "+l[0]+"/"+l[1]+"/"+l[2]+(l[3] == 0 ? "" : " leap"));
  230.             } else {
  231.                 System.err.println("ERROR! "+s[0]+"/"+s[1]+"/"+s[2]+" -> "+l[0]+"/"+l[1]+"/"+l[2]+(l[3] == 0 ? "" : " leap"));
  232.             }
  233.         }
  234.     }
  235. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement