Source for file Lunar_API.php
Documentation is available at Lunar_API.php
* Project: Lunar_API :: 양력/음력 변환 코어 클래스<br>
* 이 패키지는 양력/음력간의 변환을 제공하는 API로, 고영창님의 '진짜만세력'
* 0.92(Perl version)와 0.93(Pascal version)버전을 PHP로 포팅한 것이다.
* 이 변환 API의 유효기간은 다음과 같다.
* + -2087-02-09(음력 -2087-01-01) ~ 6078-01-29(음 6077-12-29)
* + -2087-07-05(음력 -2087-05-29) 이전은 계산이 무지 느려짐..
* + -4712-02-08 ~ 9999-12-31
* + -9999-01-01 ~ 9999-12-31
* + 64bit 계산이 가능한 시점까지 가능할 듯..
* @subpackage Lunar Core API
* @author JoungKyun.Kim <http://oops.org>
* @copyright (c) 2018, OOPS.org
* @license 고영창 (http://afnmp3.homeip.net/~kohyc/calendar/index.cgi)
* @link http://pear.oops.org/package/Lunar
* 이 패키지는 양력/음력간의 변환을 제공하는 API로, 고영창님의 '진짜만세력'
* 0.92(Perl version)와 0.93(Pascal version)버전을 PHP로 포팅한 것이다.
* 이 변환 API의 유효기간은 다음과 같다.
* + -2087-02-09(음력 -2087-01-01) ~ 6078-01-29(음 6077-12-29)
* + -2087-07-05(음력 -2087-05-29) 이전은 계산이 무지 느려짐..
* + -4712-02-08 ~ 9999-12-31
* + -9999-01-01 ~ 9999-12-31
* + 64bit 계산이 가능한 시점까지 가능할 듯..
* @subpackage Lunar Core API
* @author JoungKyun.Kim <http://oops.org>
* @copyright (c) 2018, OOPS.org
* @license 고영창 (http://afnmp3.homeip.net/~kohyc/calendar/index.cgi)
// {{{ +-- protected prpperties
0, 21355, 42843, 64498, 86335, 108366, 130578, 152958,
175471, 198077, 220728, 243370, 265955, 288432, 310767,
332928, 354903, 376685, 398290, 419736, 441060, 462295,
protected $gan = array ('갑', '을', '병', '정', '무', '기', '경', '신', '임', '계');
protected $hgan = array ('甲', '乙', '丙', '丁', '戊', '己', '庚', '辛', '壬', '癸');
protected $ji = array ('자', '축', '인', '묘', '진', '사', '오', '미', '신', '유', '술', '해');
protected $hji = array ('子', '丑', '寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌', '亥');
protected $ddi = array ('쥐', '소', '호랑이', '토끼', '용', '뱀', '말', '양', '원숭이', '닭', '개', '돼지');
// {{{ +-- public prpperties
'입춘', '우수', '경칩', '춘분', '청명', '곡우',
'입하', '소만', '망종', '하지', '소서', '대서',
'입추', '처서', '백로', '추분', '한로', '상강',
'입동', '소설', '대설', '동지', '소한', '대한',
'立春', '雨水', '驚蟄', '春分', '淸明', '穀雨',
'立夏', '小滿', '芒種', '夏至', '小暑', '大暑',
'立秋', '處暑', '白露', '秋分', '寒露', '霜降',
'立冬', '小雪', '大雪', '冬至', '小寒', '大寒',
'갑자', '을축', '병인', '정묘', '무진', '기사', '경오', '신미', '임신', '계유', '갑술', '을해',
'병자', '정축', '무인', '기묘', '경진', '신사', '임오', '계미', '갑신', '을유', '병술', '정해',
'무자', '기축', '경인', '신묘', '임진', '계사', '갑오', '을미', '병신', '정유', '무술', '기해',
'경자', '신축', '임인', '계묘', '갑진', '을사', '병오', '정미', '무신', '기유', '경술', '신해',
'임자', '계축', '갑인', '을묘', '병진', '정사', '무오', '기미', '경신', '신유', '임술', '계해'
'甲子','乙丑','丙寅','丁卯','戊辰','己巳','庚午','辛未','壬申','癸酉','甲戌','乙亥',
'丙子','丁丑','戊寅','己卯','庚辰','辛巳','壬午','癸未','甲申','乙酉','丙戌','丁亥',
'戊子','己丑','庚寅','辛卯','壬辰','癸巳','甲午','乙未','丙申','丁酉','戊戌','己亥',
'庚子','辛丑','壬寅','癸卯','甲辰','乙巳','丙午','丁未','戊申','己酉','庚戌','辛亥',
'壬子','癸丑','甲寅','乙卯','丙辰','丁巳','戊午','己未','庚申','辛酉','壬戌','癸亥'
protected $week = array ('일','월','화','수','목','금','토');
protected $hweek = array ('日','月','火','水','木','金','土');
'角','亢','氐','房','心','尾','箕',
'斗','牛','女','虛','危','室','壁',
'奎','婁','胃','昴','畢','觜','參',
'井','鬼','柳','星','張','翼','軫'
'각', '항', '저', '방', '심', '미', '기',
'두', '우', '녀', '허', '위', '실', '벽',
'규', '수', '위', '묘', '필', '자', '삼',
'정', '귀', '류', '성', '장', '익', '진'
// {{{ +-- protected (int) div ($a, $b)
protected function div ($a, $b) {
// {{{ +-- protected (int) disptimeday ($year, $month, $day)
* year의 1월 1일부터 해당 일자까지의 날자수
for ( $i= 1; $i< $month; $i++ ) {
if ( $i == 2 || $i == 4 || $i == 6 || $i == 9 || $i == 11 )
if ( ($year % 4) == 0 ) $e++ ;
if ( ($year % 100) == 0 ) $e-- ;
if ( ($year % 400) == 0 ) $e++ ;
if ( ($year % 4000) == 0 ) $e-- ;
// {{{ +-- protected (int) disp2days ($y1, $m1, $d1, $y2, $m2, $d2)
* y1,m1,d1일부터 y2,m2,d2까지의 일수 계산
protected function disp2days ($y1, $m1, $d1, $y2, $m2, $d2) {
$p1 = $p2 = $pn1 = $pp1 = $pp2 = $pr = $dis = $ppp1 = $ppp2 = $k = 0;
for ( $k = $ppp1; $k <= $ppp2; $k++ ) {
if ( $k == - 2000 && $ppp2 > 1990 ) {
} else if ( $k == - 1750 && $ppp2 > 1990 ) {
} else if ( $k ==- 1500 && $ppp2 > 1990 ) {
} else if ( $k ==- 1250 && $ppp2 > 1990 ) {
} else if ( $k ==- 1000 && $ppp2 > 1990 ) {
} else if ( $k == - 750 && $ppp2 > 1990 ) {
} else if ( $k == - 500 && $ppp2 > 1990 ) {
} else if ( $k == - 250 && $ppp2 > 1990 ) {
} else if ( $k == 0 && $ppp2 > 1990 ) {
} else if ( $k == 250 && $ppp2 > 1990 ) {
} else if ( $k == 500 && $ppp2 > 1990 ) {
} else if ( $k == 750 && $ppp2 > 1990 ) {
} else if ( $k == 1000 && $ppp2 > 1990 ) {
} else if ( $k == 1250 && $ppp2 > 1990 ) {
} else if ( $k == 1500 && $ppp2 > 1990 ) {
} else if ( $k == 1750 && $ppp2 > 1990 ) {
// {{{ +-- protected (int) getminbytime ($uy, $umm, $ud, $uh, $umin, $y1, $mo1, $d1, $h1, $mm1)
* uy,umm,ud,uh,umin과 y1,mo1,d1,h1,mm1사이의 시간(분)
function getminbytime ($uy, $umm, $ud, $uh, $umin, $y1, $mo1, $d1, $h1, $mm1) {
$dispday = $this->disp2days ($uy, $umm, $ud, $y1, $mo1, $d1);
$t = $dispday * 24 * 60 + ($uh - $h1) * 60 + ($umin - $mm1);
// {{{ +-- protected (array) getdatebymin ($tmin, $uyear, $umonth, $uday, $uhour, $umin)
* uyear,umonth,uday,uhour,umin으로부터 tmin(분)떨이진 시점의
protected function getdatebymin ($tmin, $uyear, $umonth, $uday, $uhour, $umin) {
$y1 = $mo1 = $d1 = $h1 = $mi1 = $t = 0;
$y1 = $uyear - $this->div ($tmin, 525949);
$t = $this->getminbytime ($uyear, $umonth, $uday, $uhour, $umin, $y1, 1, 1, 0, 0);
$t = $this->getminbytime ($uyear, $umonth, $uday, $uhour, $umin, $y1, $mo1, 1, 0, 0);
$t = $this->getminbytime ($uyear, $umonth, $uday, $uhour, $umin, $y1, $mo1, $d1, 0, 0);
$t = $this->getminbytime ($uyear, $umonth, $uday, $uhour, $umin, $y1, $mo1, $d1, $h1, 0);
$t = $this->getminbytime ( $uyear, $umonth, $uday, $uhour, $umin, $y1, $mo1, $d1, $h1, 0);
$t = $this->getminbytime ($uyear, $umonth, $uday, $uhour, $umin, $y1, 1, 1, 0, 0);
$t = $this->getminbytime ($uyear, $umonth, $uday, $uhour, $umin, $y1, $mo1, 1, 0, 0);
$t = $this->getminbytime ($uyear, $umonth, $uday, $uhour, $umin, $y1, $mo1, $d1, 0, 0);
$t = $this->getminbytime ($uyear, $umonth, $uday, $uhour, $umin, $y1, $mo1, $d1, $h1, 0);
$t = $this->getminbytime ($uyear, $umonth, $uday, $uhour, $umin, $y1, $mo1, $d1, $h1, 0);
return array ($y1, $mo1, $d1, $h1, $mi1);
// {{{ +-- protected (array) sydtoso24yd ($soloryear, $solormonth, $solorday, $solorhour, $solormin)
* 그레고리력의 년월시일분으로 60년의 배수, 세차, 월건(태양력),
* [1] => 29 // 60간지의 연도 배열 index
* [2] => 55 // 60간지의 월 배열 index
* [3] => 11 // 60간지의 일 배열 index
* [4] => 20 // 60간지의 시 배열 index
protected function sydtoso24yd ($soloryear, $solormonth, $solorday, $solorhour, $solormin) {
$soloryear, $solormonth, $solorday, $solorhour, $solormin
// 무인년(1996)입춘시점부터 해당일시까지 경과년수
$so24 = $this->div ($displ2min, 525949);
$so24year = ($so24 % 60) * - 1;
else if ( $so24year > 59 )
$monthmin100 = $displ2min % 525949;
$monthmin100 = 525949 - $monthmin100;
else if ( $monthmin100 >= 525949 )
for ( $i= 0; $i<= 11; $i++ ) {
if ( ($this->month[$j] <= $monthmin100) && ($monthmin100 < $this->month[$j+ 2]))
$so24day = $displ2day % 60;
else if ( $so24day > 59 )
if ( ($solorhour == 0 || $solorhour == 1) && $solormin < 30 )
else if ( ($solorhour == 1 && $solormin >= 30) || $solorhour == 2
|| ($solorhour == 3 && $solormin < 30) )
else if ( ($solorhour == 3 && $solormin >= 30) || $solorhour == 4
|| ($solorhour == 5 && $solormin < 30) )
else if ( ($solorhour == 5 && $solormin >= 30) || $solorhour == 6
|| ($solorhour == 7 && $solormin < 30) )
else if ( ($solorhour == 7 && $solormin >= 30) || $solorhour == 8
|| ($solorhour == 9 && $solormin < 30) )
else if ( ($solorhour == 9 && $solormin >= 30) || $solorhour == 10
|| ($solorhour == 11 && $solormin < 30) )
else if ( ($solorhour == 11 && $solormin >= 30) || $solorhour == 12
|| ($solorhour == 13 && $solormin < 30) )
else if ( ($solorhour == 13 && $solormin >= 30) || $solorhour == 14
|| ($solorhour == 15 && $solormin < 30) )
else if ( ($solorhour == 15 && $solormin >= 30) || $solorhour == 16
|| ($solorhour == 17 && $solormin < 30) )
else if ( ($solorhour == 17 && $solormin >= 30) || $solorhour == 18
|| ($solorhour == 19 && $solormin < 30) )
else if ( ($solorhour == 19 && $solormin >= 30) || $solorhour == 20
|| ($solorhour == 21 && $solormin < 30) )
else if ( ($solorhour == 21 && $solormin >= 30) || $solorhour == 22
|| ($solorhour == 23 && $solormin < 30) )
else if ( $solorhour == 23 && $solormin >= 30 )
return array ($so24, $so24year, $so24month, $so24day, $so24hour);
// {{{ +-- protected (array) solortoso24 ($soloryear, $solormonth, $solorday, $solorhour, $solormin)
* 그레고리력의 년월일시분이 들어있는 절기의 이름번호,
protected function solortoso24 ($soloryear, $solormonth, $solorday, $solorhour, $solormin) {
list ($so24, $so24year, $so24month, $so24day, $so24hour) =
$this->sydtoso24yd ($soloryear, $solormonth, $solorday, $solorhour, $solormin);
$soloryear, $solormonth, $solorday, $solorhour, $solormin
#$monthmin100 = $displ2min % 525949;
#$monthmin100 = 525949 - $monthmin100;
$monthmin100 = ($displ2min % 525949) * - 1;
else if ( $monthmin100 >= 525949 )
$monthmin100 = $monthmin - 525949;
$i = $so24month % 12 - 2;
else if ( $i == - 1 ) $i = 11;
$tmin = $displ2min + ($monthmin100 - $this->month[$j]);
list ($y1, $mo1, $d1, $h1, $mi1) =
$tmin = $displ2min + ($monthmin100 - $this->month[$j+ 1]);
list ($y1, $mo1, $d1, $h1, $mi1) =
$tmin = $displ2min + ($monthmin100 - $this->month[$j+ 2]);
list ($y1, $mo1, $d1, $h1, $mi1) =
$inginame, $ingiyear, $ingimonth, $ingiday, $ingihour, $ingimin,
$midname, $midyear, $midmonth, $midday, $midhour, $midmin,
$outginame, $outgiyear, $outgimonth, $outgiday, $outgihour, $outgimin
// {{{ +-- protected (int) degreelow ($d)
$i = $this->div ((int) $d, 360);
while ( $di >= 360 || $di < 0 ) {
// {{{ +-- protected (int) moonsundegree ($day)
* 태양황력과 달황경의 차이 (1996 기준)
$sl = (float) ($day * 0.98564736 + 278.956807); // 평균 황경
$smin = 282.869498 + 0.00004708 * $day; // 근일점 황경
$sminangle = 3.14159265358979 * ($sl - $smin) / 180; // 근점이각
$sd = 1.919 * sin ($sminangle) + 0.02 * sin (2 * $sminangle); // 황경차
$sreal = $this->degreelow ($sl + $sd); // 진황경
$ml = 27.836584 + 13.17639648 * $day; // 평균 황경
$mmin = 280.425774 + 0.11140356 * $day; // 근지점 황경
$mminangle = 3.14159265358979 * ($ml - $mmin) / 180; // 근점이각
$msangle = 202.489407 - 0.05295377 * $day; // 교점황경
$msdangle = 3.14159265358979 * ($ml - $msangle) / 180;
$md = 5.06889 * sin ($mminangle)
+ 0.146111 * sin (2 * $mminangle)
+ 0.01 * sin (3 * $mminangle)
- 0.238056 * sin ($sminangle)
- 0.087778 * sin ($mminangle + $sminangle)
+ 0.048889 * sin ($mminangle - $sminangle)
- 0.129722 * sin (2 * $msdangle)
- 0.011111 * sin (2 * $msdangle - $mminangle)
- 0.012778 * sin (2 * $msdangle + $mminangle); // 황경차
$mreal = $this->degreelow ($ml + $md); // 진황경
// {{{ +-- protected (array) getlunarfirst ($syear, $smonth, $sday)
* 그레고리력 년월일이 들어있는 태음월의 시작합삭일지, 망일시,
* [0] => 2013 // 시작 합삭 년도
* [10] => 2013 // 끝 합삭 년도
$dm = $this->disp2days ($syear, $smonth, $sday, 1995, 12, 31);
list ($year, $month, $day, $hour, $min)= $this->getdatebymin ($i, 1995, 12, 31, 0, 0);
list ($year2, $month2, $day2, $hour2, $min2) = $this->getdatebymin ($i, 1995, 12, 31, 0, 0);
if ( $smonth == $month2 && $sday == $day2 ) {
list ($year2, $month2, $day2, $hour2, $min2) = $this->getdatebymin ($i, 1995, 12, 31, 0, 0);
$d = $this->disp2days ($year, $month, $day, 1995, 12, 31);
while ( $de < 179.999 ) {
list ($year1, $month1, $day1, $hour1, $min1) = $this->getdatebymin ($i, 1995, 12, 31, 0, 0);
$year, $month, $day, $hour, $min,
$year1, $month1, $day1, $hour1, $min1,
$year2, $month2, $day2, $hour2, $min2
// {{{ +-- protected (array) solartolunar ($solyear,$solmon,$solday)
* [3] => // 음력 윤달 여부 (boolean)
* [4] => 1 // 평달(false)/큰달(true) 여부 (boolean)
protected function solartolunar ($solyear, $solmon, $solday) {
list ($smoyear, $smomonth, $smoday, $smohour, $smomin,
$y0, $mo0, $d0, $h0, $mi0, $y1, $mo1, $d1, $h1, $mi1)
$lday = $this->disp2days ($solyear, $solmon, $solday, $smoyear, $smomonth, $smoday)+ 1;
$i= abs ($this->disp2days ($smoyear, $smomonth, $smoday, $y1, $mo1, $d1));
list ($inginame, $ingiyear, $ingimonth, $ingiday, $ingihour, $ingimin,
$midname1, $midyear1, $midmonth1, $midday1, $midhour1, $midmin1,
$outginame, $outgiyear, $outgimonth, $outgiday, $outgihour, $outgimin)
= $this->solortoso24 ($smoyear, $smomonth, $smoday, $smohour, $smomin);
$midname2 = $midname1 + 2;
$s0 = $this->month[$midname2] - $this->month[$midname1];
list ($midyear2, $midmonth2, $midday2, $midhour2, $midmin2)
= $this->getdatebymin ($s0, $midyear1, $midmonth1, $midday1, $midhour1, $midmin1);
if ( ($midmonth1 == $smomonth && $midday1 >= $smoday) || ($midmonth1 == $mo1 && $midday1 < $d1) ) {
$lmonth = ($midname1 - 1) / 2 + 1;
if ( ($midmonth2 == $mo1 && $midday2< $d1) || ($midmonth2 == $smomonth && $midday2 >= $smoday) ) {
$lmonth = ($midname2 - 1) / 2 + 1;
if ( $smomonth < $midmonth2 && $midmonth2 < $mo1 ) {
$lmonth = ($midname2 - 1) / 2 + 1;
$lmonth = ($midname1 - 1) / 2 + 1;
if ( $lmonth == 12 && $smomonth == 1 )
if ( ($lmonth == 11 && $leap == 1) || $lmonth == 12 || $lmonth < 6 ) {
list ($midyear1, $midmonth1, $midday1, $midhour1, $midmin1)
= $this->getdatebymin (2880, $smoyear, $smomonth, $smoday, $smohour, $smomin);
list ($outgiyear, $outgimonth, $outgiday, $lnp, $lnp2)
if ( $outgiday == $outgimonth ) {
if ( $lmonth != $outgimonth ) {
if ( $lmonth == $outgimonth ) {
return array ($lyear, $lmonth, $lday, $leap ? true : false, $largemonth ? true : false);
// {{{ +-- protected (array) lunartosolar ($lyear, $lmonth, $lday, $leap)
protected function lunartosolar ($lyear, $lmonth, $lday, $leap = false) {
list ($inginame, $ingiyear, $ingimonth, $ingiday, $ingihour, $ingimin,
$midname, $midyear, $midmonth, $midday, $midhour, $midmin,
$outginame, $outgiyear, $outgimonth, $outgiday, $outgihour, $outgimin)
$midname = $lmonth * 2 - 1 ;
$tmin = $this->month[$midname] * - 1;
list ($midyear, $midmonth, $midday, $midhour, $midmin)
= $this->getdatebymin ($tmin, $ingiyear, $ingimonth, $ingiday, $ingihour, $ingimin);
list ( $outgiyear, $outgimonth, $outgiday, $hour, $min,
$yearm, $monthm1, $daym, $hourm, $minm,
$year1, $month1, $day1, $hour1, $min1 )
list ($lyear2, $lmonth2, $lday2, $lnp, $lnp2)
if ( $lyear2 == $lyear && $lmonth == $lmonth2 ) {
$tmin = - 1440 * $lday + 10;
list ($syear, $smonth, $sday, $hour, $min)
= $this->getdatebymin ($tmin, $outgiyear, $outgimonth, $outgiday, 0, 0);
list ($lyear2, $lmonth2, $lday2, $lnp, $lnp2)
if ( $lyear2== $lyear && $lmonth== $lmonth2 ) {
$tmin = - 1440 * $lday + 10;
list ($syear, $smonth, $sday, $hour, $min)
= $this->getdatebymin ($tmin, $year1, $month1, $day1, 0, 0);
list ($lyear2, $lmonth2, $lday2, $lnp, $lnp2)
if ( $lyear2 == $lyear && $lmonth == $lmonth2 ) {
$tmin = - 1440 * $lday + 10;
list ($syear, $smonth, $sday, $hour, $min)
= $this->getdatebymin ($tmin, $year1, $month1, $day1, 0, 0);
return array ($syear, $smonth, $sday);
// {{{ +-- protected (int) getweekday ($syear, $smonth, $sday)
* 그레고리력 날자를 요일의 배열 번호로 변환
protected function getweekday ($syear, $smonth, $sday) {
while ( $d > 6 || $d < 0 ) {
// {{{ +-- protected (int) get28sday ($syear, $smonth, $sday)
protected function get28sday ($syear, $smonth, $sday) {
$i = $this->div ($d, 28);
while ( $d > 27 || $d < 0 ) {
* vim: set filetype=php noet sw=4 ts=4 fdm=marker:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
|