'PHP 음력 양력 변환 코드'에 해당되는 글 1건

728x90

[ 태음력의 조정 ]
    235회합월은 일수로는 6940일(days)이다(235 x 29.530588일 = 6939.68818일).
    6940일의 1/19은 6940일 / 19 = 365.263157894737일(365 + 1/4 + 1/76일)이다.
    365.263157894737일은 12회합월(synodic months)인
    12 x 29.530588일 = 354.367056일보다 10.896101894737일(365.263157894737 - 354.367056) 더 크다.
    이것이 뜻하는 바는 음력으로 1년이 지나면 태양력과는 약 11일의 차이가 난다는 것을 의미한다.
    따라서 음력으로 3년이 지나면 태양력과는 약 33일의 차이가 나게 된다.
    따라서 3년마다 음력에 1달을 추가하며 13개의 음력 달들이 있게 하면,
    태음력은 어느 정도 근사하게 태양력과 일치하게 된다.
    태양력 19년 동안에 이런 작업을 총 7번(19년/3년 = 6.33) 행하면 된다.
    이런 이유로, 메톤 주기를 19년 7윤법이라고도 하였다.
 
메톤은 19태양년을 6,940일로 보고,
이것을 큰달(30일) 125개월과 작은달(29일) 110개월의 총 235개월 6,940일로 배분하였다.
이 방법은 평년(12개월) 12년과 윤년(13개월) 7년의 총 235개월로
태음력 달력을 구성하는 것과 동일하므로 19년 7윤법이라고도 하였다.

메톤주기의 존재를 알 수 있는 예로,
특정한 양력 날짜와 그에 대응하는 음력 날짜는 19년이 지나면 다시 일치한다는 사실을 찾을 수 있다.

하지만 정확히 맞물리는 건 아니라서 하루 정도 어긋나기도 한다. 


음력 날짜는 어느 경도를 기준으로 했느냐에 따라 하루 정도 차이가 있어서 때려 맞춰야 한다는 얘기가 있다.

한국천문연구원에서 계산한 2050년까지 음양력 자료들이 수록된 만세력을 기준으로 음력 날짜를 맞추면 될 거 같다.

음력을 알아내는 일정한 규칙은 없다고 한다.

아래 변환 코드로 내 생년월일, 딸래미 생년월일을 양력 → 음력 변환을 했을 때는 정확하게 결과가 도출되었다.


검색한 걸 참고하면 도움될 거 같아서 링크를 걸어둔다.

http://lifesci.net/pod/bbs/board.php?bo_table=B01&wr_id=1917



PHP 달력 만들기 https://link2me.tistory.com/1545 코드에 있는 함수를 자바 코드로 변환을 했다.

자동 변환이 아니라 코드에 맞게 함수를 찾아서 수정했다.

음력이 지원되는 Custom 달력을 만들어 볼 목적으로 코드를 변환하여 테스트 해보는 중이다.

PHP 원본 코드와 Java 로 변환한 코드를 같이 첨부했다.

Java 변환 코드는 Android 에서 활용하기 위한 목적이라 Android Studio 에서 작성했다.


PHP 코드

lun2sol.php



Lunar2Solar.java

Lunar2Solar.java

Lunar2Solar.java


자바 음력/양력 변환 코드

public class Lunar2Solar {
    // 음력 데이터 (평달 - 작은달 :1,  큰달:2 )
    // (윤달이 있는 달 - 평달이 작고 윤달도 작으면 :3 , 평달이 작고 윤달이 크면 : 4)
    // (윤달이 있는 달 - 평달이 크고 윤달이 작으면 :5,  평달과 윤달이 모두 크면 : 6)
    final static String[] LunarInfo = new String[]
            {"1212122322121","1212121221220","1121121222120","2112132122122","2112112121220",
                "2121211212120","2212321121212","2122121121210","2122121212120","1232122121212",
                "1212121221220","1121123221222","1121121212220","1212112121220","2121231212121",
                "2221211212120","1221212121210","2123221212121","2121212212120","1211212232212",
                "1211212122210","2121121212220","1212132112212","2212112112210","2212211212120",
                "1221412121212","1212122121210","2112212122120","1231212122212","1211212122210",
                "2121123122122","2121121122120","2212112112120","2212231212112","2122121212120",
                "1212122121210","2132122122121","2112121222120","1211212322122","1211211221220",
                "2121121121220","2122132112122","1221212121120","2121221212110","2122321221212",
                "1121212212210","2112121221220","1231211221222","1211211212220","1221123121221",
                "2221121121210","2221212112120","1221241212112","1212212212120","1121212212210",
                "2114121212221","2112112122210","2211211412212","2211211212120","2212121121210",
                "2212214112121","2122122121120","1212122122120","1121412122122","1121121222120",
                "2112112122120","2231211212122","2121211212120","2212121321212","2122121121210",
                "2122121212120","1212142121212","1211221221220","1121121221220","2114112121222",
                "1212112121220","2121211232122","1221211212120","1221212121210","2121223212121",
                "2121212212120","1211212212210","2121321212221","2121121212220","1212112112210",
                "2223211211221","2212211212120","1221212321212","1212122121210","2112212122120",
                "1211232122212","1211212122210","2121121122210","2212312112212","2212112112120",
                "2212121232112","2122121212110","2212122121210","2112124122121","2112121221220",
                "1211211221220","2121321122122","2121121121220","2122112112322","1221212112120",
                "1221221212110","2122123221212","1121212212210","2112121221220","1211231212222",
                "1211211212220","1221121121220","1223212112121","2221212112120","1221221232112",
                "1212212122120","1121212212210","2112132212221","2112112122210","2211211212210",
                "2221321121212","2212121121210","2212212112120","1232212122112","1212122122110",
                "2121212322122","1121121222120","2112112122120","2211231212122","2121211212120",
                "2122121121210","2124212112121","2122121212120","1212121223212","1211212221220",
                "1121121221220","2112132121222","1212112121220","2121211212120","2122321121212",
                "1221212121210","2121221212120","1232121221212","1211212212210","2121123212221",
                "2121121212220","1212112112220","1221231211221","2212211211220","1212212121210",
                "2123212212121","2112122122120","1211212322212","1211212122210","2121121122120",
                "2212114112122","2212112112120","2212121211210","2212232121211","2122122121210",
                "2112122122120","1231212122212","1211211221220","2121121321222","2121121121220",
                "2122112112120","2122141211212","1221221212110","2121221221210","2114121221221"};

    final static int[] arrayLDAY = new int[]{31,0,31,30,31,30,31,31,30,31,30,31};

    public static String lun2sol(String yyyymmdd) {
        int YunMonthFlag = 0;
        int gf_lun2sol = 0;
        int gf_yun = 0;
        int leap = 0;
        int syear = 0;
        int smonth = 0;
        int sday = 0;

        int getYEAR = Integer.parseInt(yyyymmdd.substring(0,4));
        int getMONTH = Integer.parseInt(yyyymmdd.substring(4,6));
        int getDAY = Integer.parseInt(yyyymmdd.substring(6,8));

        String arrayYUKSTR="甲-乙-丙-丁-戊-己-庚-辛-壬-癸";
        String[] arrayYUK = arrayYUKSTR.split("-");

        String arrayGAPSTR="子-丑-寅-卯-辰-巳-午-未-申-酉-戌-亥";
        String[] arrayGAP = arrayGAPSTR.split("-");

        String arrayDDISTR="쥐-소-범-토끼-용-뱀-말-양-원숭이-닭-개-돼지";
        String[] arrayDDI = arrayDDISTR.split("-");

        String arrayWEEKSTR="일-월-화-수-목-금-토";
        String[] arrayWEEK = arrayWEEKSTR.split("-");

        if (getYEAR <= 1881 || getYEAR >= 2050) { //년수가 해당일자를 넘는 경우
            YunMonthFlag = 0;
        }

        if (getMONTH > 12) { // 달수가 13이 넘는 경우
            YunMonthFlag = 0;
        }

        int m1 = getYEAR - 1881;
        if (Integer.parseInt(LunarInfo[m1].substring(12,13)) == 0) { // 윤달이 없는 해임
            YunMonthFlag = 0;
        } else {
            if (Integer.parseInt(LunarInfo[m1].substring(getMONTH,getMONTH+1)) > 2) {
                YunMonthFlag = 1;
            } else {
                YunMonthFlag = 0;
            }
        }

        m1 = -1;
        int td = 0;

        if (getYEAR > 1881 && getYEAR < 2050) {
            m1 = getYEAR - 1882;
            for (int i=0; i <= m1; i++) {
                for (int j=0; j <= 12; j++) {
                    td = td + Integer.parseInt(LunarInfo[i].substring(j,j+1));
                }
                if (Integer.parseInt(LunarInfo[i].substring(12,13)) == 0) {
                    td = td + 336;
                } else {
                    td = td + 362;
                }
            }
        } else {
            gf_lun2sol = 0;
        }

        m1++;
        int n2 = getMONTH - 1;
        int m2 = -1;

        while(true) {
            m2++;
            if (Integer.parseInt(LunarInfo[m1].substring(m2,m2+1)) > 2) {
                td = td + 26 + Integer.parseInt(LunarInfo[m1].substring(m2,m2+1));
                n2++;
            } else {
                if (m2 == n2) {
                    if (gf_yun == 1) {
                        td = td + 28 + Integer.parseInt(LunarInfo[m1].substring(m2,m2+1));
                    }
                    break;
                } else {
                    td = td + 28 + Integer.parseInt(LunarInfo[m1].substring(m2,m2+1));
                }
            }
        }

        td = td + getDAY + 29;
        m1 = 1880;
        while(true) {
            m1++;
            if (m1 % 400 == 0 || m1 % 100 != 0 && m1 % 4 == 0) {
                leap = 1;
            } else {
                leap = 0;
            }

            if (leap == 1) {
                m2 = 366;
            } else {
                m2 = 365;
            }

            if (td < m2) break;
            td = td - m2;
        }
        syear = m1;
        arrayLDAY[1] = m2 - 337;

        m1 = 0;

        while(true) {
            m1++;
            if (td <= arrayLDAY[m1-1]) {
                break;
            }
            td = td - arrayLDAY[m1-1];
        }
        smonth = m1;
        sday = td;
        int y = syear - 1;
        td = (int)(y*365) + (int)(y/4) - (int)(y/100) + (int)(y/400);

        if (syear % 400 == 0 || syear % 100 != 0 && syear % 4 == 0) {
            leap = 1;
        } else {
            leap = 0;
        }

        if (leap == 1) {
            arrayLDAY[1] = 29;
        } else {
            arrayLDAY[1] = 28;
        }
        for (int i=0; i <= smonth-2; i++) {
            td = td + arrayLDAY[i];
        }
        td = td + sday;
        int w = td % 7;

        String sweek = arrayWEEK[w];
        gf_lun2sol = 1;

        return String.valueOf(syear+String.format("%02d", smonth)+String.format("%02d", sday));
    }

    public static String sol2lun(String yyyymmdd) {
        int gf_sol2lun = 0;
        int gf_yun = 0;

        int getYEAR = Integer.parseInt(yyyymmdd.substring(0,4));
        int getMONTH = Integer.parseInt(yyyymmdd.substring(4,6));
        int getDAY = Integer.parseInt(yyyymmdd.substring(6,8));

        String arrayYUKSTR="甲-乙-丙-丁-戊-己-庚-辛-壬-癸";
        String[] arrayYUK = arrayYUKSTR.split("-");

        String arrayGAPSTR="子-丑-寅-卯-辰-巳-午-未-申-酉-戌-亥";
        String[] arrayGAP = arrayGAPSTR.split("-");

        String arrayDDISTR="쥐-소-범-토끼-용-뱀-말-양-원숭이-닭-개-돼지";
        String[] arrayDDI = arrayDDISTR.split("-");

        String arrayWEEKSTR="일-월-화-수-목-금-토";
        String[] arrayWEEK = arrayWEEKSTR.split("-");


        Long[] dt = new Long[LunarInfo.length];
        for (int i = 0; i < LunarInfo.length; i++) {
            dt[i] = Long.parseLong(LunarInfo[i]);
        }
        for (int i=0; i <= 168; i++) {
            dt[i] = Long.valueOf(0);
            for (int j=0;j < 12;j++) {
                switch (Integer.parseInt(LunarInfo[i].substring(j,j+1))) {
                    case 1:
                        dt[i] += 29;
                        break;
                    case 3:
                        dt[i] += 29;
                        break;
                    case 2:
                        dt[i] += 30;
                        break;
                    case 4:
                        dt[i] += 30;
                        break;
                }
            }

            switch (Integer.parseInt(LunarInfo[i].substring(12,13))) {
                case 0:
                    break;
                case 1:
                    dt[i] += 29;
                    break;
                case 3:
                    dt[i] += 29;
                    break;
                case 2:
                    dt[i] += 30;
                    break;
                case 4:
                    dt[i] += 30;
                    break;
            }
        }

        int td1 = 1880 * 365 + (int)(1880/4) - (int)(1880/100) + (int)(1880/400) + 30;
        int k11 = getYEAR - 1;

        int td2 = k11 * 365 + (int)(k11/4) - (int)(k11/100) + (int)(k11/400);

        if (getYEAR % 400 == 0 || getYEAR % 100 != 0 && getYEAR % 4 == 0) {
            arrayLDAY[1] = 29;
        } else {
            arrayLDAY[1] = 28;
        }

        if (getMONTH > 13) {
            gf_sol2lun = 0;
        }

        if (getDAY > arrayLDAY[getMONTH-1]) {
            gf_sol2lun = 0;
        }

        for (int i=0;i <= getMONTH-2;i++) {
            td2 += arrayLDAY[i];
        }

        td2 += getDAY;
        int td = td2 - td1 + 1;
        Long td0 = dt[0];

        int jcount = 0;
        int ryear = 0;
        int m1 = 0;
        int m2 = 0;
        int i = 0;
        for (i=0; i <= 168; i++) {
            if (td <= td0) {
                break;
            }
            td0 += dt[i + 1];
        }
        ryear = i + 1881;
        td0 -= dt[i];
        td -= td0;

        if (Integer.parseInt(LunarInfo[i].substring(12,13)) == 0) {
            jcount = 11;
        } else {
            jcount = 12;
        }

        for (int j=0;j <= jcount;j++) { // 달수 check, 윤달 > 2 (by harcoon)
            if (Integer.parseInt(LunarInfo[i].substring(j,j+1)) <= 2) {
                m2++;
                m1 = Integer.parseInt(LunarInfo[i].substring(j,j+1)) + 28;
                gf_yun = 0;
            } else {
                m1 = Integer.parseInt(LunarInfo[i].substring(j,j+1)) + 26;
                gf_yun = 1;
            }
            if (td <= m1) {
                break;
            }
            td = td - m1;
        }

        int k1=(ryear+6) % 10;
        String syuk = arrayYUK[k1];
        int k2=(ryear+8) % 12;
        String sgap = arrayGAP[k2];
        String sddi = arrayDDI[k2];

        gf_sol2lun = 1;

        return String.valueOf(ryear+String.format("%02d", m2)+String.format("%02d", td)+"|"+syuk+sgap+"년|"+sddi+"띠");
    }

}


샘플 코드

import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import com.tistory.link2me.util.LunarCalendar;
import java.util.Calendar;

public class CalendarActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_calendar);

        System.out.println("이순신 음력 => 양력 : "+ Lunar2Solar.lun2sol("19961112"));
        System.out.println("홍길동 양력 => 음력 : "+ Lunar2Solar.sol2lun("20010125"));
    }

}
 


Logcat

I/System.out: 이순신 음력 => 양력 : 19961222
I/System.out: 홍길동 양력 => 음력 : 2001|01|02|신사년|뱀띠

이 음력/양력 변환 코드가 자바 버전으로 돌아다니는 것은 없는거 같다.

PHP 코드를 자바로 변환한 것이지만 나름 유용하게 사용할 수 있을 것으로 본다.


이 글이 도움 되었다면 XX 클릭 해주세요. 좋은 자료 올리는데 큰 힘이 됩니다.

블로그 이미지

Link2Me

,