<?php
##
## this file name is 'class.solar.php'
##
## solar object -- get sun position or 24 solar terms
##
## [author]
## - Chilbong Kim, <san2(at)linuxchannel.net>
## - http://linuxchannel.net/
##
## [changes]
## - 2003.09.08 : bug fixed
## - 2003.09.06 : new build
##
## [근사식에 대한 신뢰]
## - 표준편차 : 1289.7736 = 21.5 minutes (standard deviation)
## - 평균오차 : 817.57409541246 = 13.6 minutes
## - 최대오차 : +4102.7340(68.4 minutes), -4347.2395(72.5 minutes)
##
## [근사식으로 계산한 24절기 실제 오차] 1902 ~ 2037 년
## - 표준편차 : 1122.1921 = 18.7 분
## - 평균오차 : +686.08382175161 = +11.4 분
## - 최대오차 : +4297.252300024(71.6 분), -4278.048699975(71.3 분)
## - 최소오차 : +0.16999998688698(0초)
##
## [근사식 + 년도 보정으로 계산한 24절기 실제 오차] 1902 ~ 2037 년
## - 표준편차 : 450.8534 = 7.5 분
## - 평균오차 : +305.38638890903 = 5.0 분
## - 최대오차 : +3028.2343000174 = 50.5 분, -1982.9391000271 = 33.1 분
## - 최소오차 : +0.0085000991821289 = 0 초
##
## [valid date]
## - 1902.01.01 00:00:00 <= utime <= 2037.12.31 23:59:59
##
## [download & online source view]
## - http://ftp.linuxchannel.net/devel/php_solar/
##
## [demo]
## - http://linuxchannel.net/gaggle/solar.php
##
## [references]
## - http://cgi.chollian.net/~kohyc/
## - http://user.chollian.net/~kimdbin/
## - http://user.chollian.net/~kimdbin/re/calendar.html
## - http://user.chollian.net/~kimdbin/re/suncoord.html
## - http://user.chollian.net/~kimdbin/qna/al138.html
## - http://ruby.kisti.re.kr/~manse/contents-3.html
## - http://ruby.kisti.re.kr/~anastro/sub_index.htm
## - http://www-ph.postech.ac.kr/~obs/lecture/lec1/elementary/nakedeyb.htm
## - http://ruby.kisti.re.kr/~anastro/calendar/etime/ETime.html
## - http://www.sundu.co.kr/5-information/5-3/5f3-3-5-04earth-1.htm
## - http://www-ph.postech.ac.kr/~obs/lecture/lec1/elementary/nakedeya.htm
## - http://upgradename.com/calm.php
## - http://aa.usno.navy.mil/faq/docs/SunApprox.html
## - http://aa.usno.navy.mil/data/docs/JulianDate.html
##
## [usage]
##
## [example]
## $sun = array();
## $terms = solar::terms(date('Y'),1,12,&$sun);
## print_r($terms);
## print_r($sun);
## print_r(solar::sun(time()));
##
class solar
{
## check solar terms in today or tomorrow
##
function &solar($utime=0, $GMT=FALSE)
{
return solar::today($utime,$GMT);
}
function &today($utime=0, $GMT=FALSE)
{
if(func_num_args() < 1) $utime = time();
if($GMT) $utime -= 32400;
list($year,$moon,$moonday) = explode(' ',date('Y n nd',$utime));
$terms = solar::terms($year,$moon,0);
if($term = $terms[$moonday])
{
$str = '오늘은 <B>'.$term.'</B>입니다.';
}
else if($term = $terms[date('nd',$utime+86400)])
{
$str = '내일은 <B>'.$term.'</B>입니다.';
}
return $str;
}
## get sun position at unix timestamp
##
## [limit]
## - mktime(0,0,0,1,1,1902) < $utime < mktime(23,59,59,12,31,2037)
##
## [study]
## - w = 23.436
## - tan RA = (sin L * cos w - tan e * sin w ) / cos L
## - sin d = (sin e * cos w) + (cos e * sin w * sin L)
##
## [example]
## - print_r(solar::sun(mktime( 10,0,0,3,21,2003) ));
## - print_r(solar::sun(mktime(10-9,0,0,3,21,2003),1)); // same as
##
function &sun($utime, $GMT=FALSE)
{
static $L=0, $D = 0, $JD = 0;
static $deg2rad = array();
if($utime<-2145947400 || $utime>2145884399)
{
echo "\n".'error: invalid input '.$utime.
', 1902.01.01 00:00:00 <= utime <= 2037.12.31 23:59:59'."\n";
return -1;
}
list($L,$atime) = solar::sunl($utime,$GMT,&$D,&$JD,&$deg2rad);
## Sun's ecliptic, in degress
##
$e = sprintf('%.10f',23.439 - (0.00000036*$D)); // degress
$cosg = cos($deg2rad['g']); // degress
$cos2g = cos($deg2rad['2g']); // degress
## R == AU (sun ~ earth)
## The distance of the Sun from the Earth, R, in astronomical units (AU)
##
$R = sprintf('%.10f',1.00014 - (0.01671*$cosg) - (0.00014*$cos2g));
## convert
##
$deg2rad['e'] = deg2rad($e); // radian
$deg2rad['L'] = deg2rad($L); // radian
$cose = cos($deg2rad['e']); // degress
$sinL = sin($deg2rad['L']); // degress
$cosL = cos($deg2rad['L']); // degress
$sine = sin($deg2rad['e']); // degress
## the Sun's right ascension, RA, and declination, d
##
$tanRA = sprintf('%.10f',$cose * $sinL / $cosL); // degress
$sind = sprintf('%.10f',$sine * $sinL); // degress
//$RA = sprintf('%.10f',rad2deg(atan($tanRA))+180);
$RA = sprintf('%.10f',rad2deg(atan($tanRA)));
$RA = solar::deg2valid($RA);
$d = sprintf('%.10f',rad2deg(asin($sind))); // Sun's declination, degress
$solartime = solar::deg2solartime($L);
$daytime = solar::deg2daytime($RA);
//if(!($L1=round($L) % 15))
//{
// $idx = $L1 / 15;
// list($hterms) = solar::gterms();
//}
## all base degress or decimal
##
return array
(
'JD' => $JD, /*** Julian Date ***/
'L' => $L, /*** Sun's geocentric apparent ecliptic longitude ***/
'e' => $e, /*** Sun's ecliptic ***/
'R' => $R, /*** Sun from the Earth, astronomical units (AU) ***/
'RA' => $RA, /*** Sun's right ascension ***/
'd' => $d, /*** Sun's declination ***/
'stime' => $solartime, /*** solar time ***/
'dtime' => $daytime, /*** day time ***/
'atime' => $atime, /*** append time for integer degress **/
'utime' => $utime, /*** unix timestamp ***/
'date' => date('D, d M Y H:i:s T',$utime), /*** KST date ***/
'gmdate' => gmdate('D, d M Y H:i:s T',$utime), /*** GMT date ***/
'_L' => solar::deg2angle($L),
'_e' => solar::deg2angle($e,1),
'_RA' => solar::deg2angle($RA),
'_d' => solar::deg2angle($d,1),
'_stime' => solar::time2htime($solartime),
'_dtime' => solar::time2htime($daytime),
'_atime' => solar::time2htime($atime,TRUE),
);
}
function &sunl($utime, $GMT=FALSE, $D=0, $JD=0, $deg2rad=array())
{
if($GMT) $utime += 32400; // GMT to KST
## D -- get the number of days from base JD
## D = JD(Julian Date) - 2451545.0, base JD(J2000.0)
##
## base position (J2000.0), 2000-01-01 12:00:00, UT
## as mktime(12,0,0-64,1,1,2000) == 946695536 unix timestamp at KST
## as gmmktime(12,0,0-64,1,1,2000) == 946727936 unix timestamp at GMT
##
$D = $utime - 946727936; // number of time
$D = sprintf('%.10f',$D/86400); // float, number of days
$JD = sprintf('%.10f',$D+2451545.0); // float, Julian Date
$g = sprintf('%.10f',357.529 + (0.98560028 * $D));
$q = sprintf('%.10f',280.459 + (0.98564736 * $D));
## fixed
##
$g = solar::deg2valid($g); // to valid degress
$q = solar::deg2valid($q); // to valid degress
## convert
##
$deg2rad = array();
$deg2rad['g'] = deg2rad($g); // radian
$deg2rad['2g'] = deg2rad($g*2); // radian
$sing = sin($deg2rad['g']); // degress
$sin2g = sin($deg2rad['2g']); // degress
## L is an approximation to the Sun's geocentric apparent ecliptic longitude
##
$L = sprintf('%.10f',$q + (1.915 * $sing) + (0.020*$sin2g));
$L = solar::deg2valid($L); // degress
$atime = solar::deg2solartime(round($L)-$L); // float
return array($L,$atime); // array, float degress, float seconds
}
/***
function &sinl($f, $v)
{
return sin(deg2rad($f+$v));
}
## http://linux-sarang.net/board/?p=read&table=qa&no=198189
## -2 < sin x < + 2
## sin (77 + L) ==> (77 + L - 1.915 sin (77 + L))
##
function &l2d($L)
{
$L = (int)$L; // 0 <= $L <= 345
//$sinl = sin(deg2rad(77+$L));
$sinl = solar::sinl($L,77);
//$sinl = solar::sinl($L-(1.915)*$sinl,77);
//$sin2l = sin(deg2rad(154+($L*2)));
$sin2l = solar::sinl($L*2,154);
$sin2l = solar::sinl($L-(0.020*$L*2*$sin2l),154);
$sin2l = solar::sinl($L-(0.020*$L*2*$sin2l),154);
$D = sprintf('%.10f',
($L - 280.459 - (1.915 * $sinl) - (0.020 * $sin2l)) / 0.98564736);
return $D; // float
}
function &l2jd($L)
{
$D = solar::l2d($L);
$JD = sprintf('%.10f',$D+2451545.0);
//$JD = $JD + ($i * 360 / 0.98564736)
return $JD; // float
}
function &l2utime($year, $L, $GMT=FLASE)
{
$i = (int)$year - 2000 + 1;
$D = solar::l2d($L);
$utime = ($D * 86400) + 946727936 + (31556925.216 * $i);
$utime = round($utime);
return $utime - ($GMT ? 32400 : 0); // integer
}
***/
## 1 hour == 15 degress
## 1 degress == 4 minute == 240 seconds
##
function °2daytime($deg)
{
return sprintf('%.4f',$deg*240); // seconds
}
## 1 solar year == 365.242190 days == 31556925.216 seconds
## 1 degress == 31556925.216 seconds / 360 degress == 87658.1256 seconds
##
function °2solartime($deg)
{
return sprintf('%.4f',$deg*87658.1256); // seconds
}
function °2angle($deg, $singed=FALSE)
{
if($singed) $singed = '+';
if($deg <0) { $singed = '-'; $deg = abs($deg); }
$time = sprintf('%.4f',$deg*3600);
$degr = (int)$deg.chr(161).chr(198); //sprintf('%d',$deg);
$time = sprintf('%.4f',$time-($degr*3600)); // fmod
$mins = sprintf('%02d',$time/60).chr(161).chr(199);
$secs = sprintf('%.4f',$time-($mins*60)).chr(161).chr(200); // fmod
return $singed.$degr.$mins.$secs;
}
function °2valid($deg)
{
if($deg <= 360 && $deg >=0) return $deg;
while($deg > 360) $deg = sprintf('%.10f',$deg - 360);
while($deg < 0) $deg = sprintf('%.10f',$deg + 360);
return (float)$deg; // float degress
}
function &moon2valid($moon)
{
//$moon = max($moon,1);
//$moon = min($moon,12);
if($moon < 1) $moon = 1;
else if($moon > 12) $moon = 12;
return (int)$moon;
}
function &time2htime($time, $singed=FALSE)
{
if($singed) $singed = '+';
if($time<0) { $singed = '-'; $time = abs($time); }
$days = (int)($time/86400); //sprintf('%03d',$time/86400);
$time = sprintf('%.4f',$time-($days*86400)); // fmod
$hour = sprintf('%02d',$time/3600);
$time = sprintf('%.4f',$time-($hour*3600)); // fmod
$mins = sprintf('%02d',$time/60);
$secs = sprintf('%.4f',$time-($mins*60)); // fmod
return $singed.$days.' '.$hour.' '.$mins.' '.$secs;
}
function >erms()
{
## mktime(7+9,36,19-64,3,20,2000), 2000-03-20 16:35:15(KST)
##
if(!defined('__SOLAR_START__'))
{
define('__SOLAR_START__',953537715); // start base unix timestamp
define('__SOLAR_TYEAR__',31556940); // tropicalyear to seconds
define('__SOLAR_BYEAR__',2000); // start base year
}
$hterms = array
(
'소한','대한','입춘','우수','경칩','춘분','청명','곡우',
'입하','소만','망종','하지','소서','대서','입추','처서',
'백로','추분','한로','상강','입동','소설','대설','동지'
);
$tterms = array
(
-6418939, -5146737, -3871136, -2589569, -1299777, 0,
1310827, 2633103, 3966413, 5309605, 6660762, 8017383,
9376511, 10735018, 12089855, 13438199, 14777792, 16107008,
17424841, 18731368, 20027093, 21313452, 22592403, 23866369
);
return array($hterms,$tterms);
}
function &tterms($year)
{
$addstime = array
(
1902=> 1545, 1903=> 1734, 1904=> 1740, 1906=> 475, 1907=> 432,
1908=> 480, 1909=> 462, 1915=> -370, 1916=> -332, 1918=> -335,
1919=> -263, 1925=> 340, 1927=> 344, 1928=> 2133, 1929=> 2112,
1930=> 2100, 1931=> 1858, 1936=> -400, 1937=> -400, 1938=> -342,
1939=> -300, 1944=> 365, 1945=> 380, 1946=> 400, 1947=> 200,
1948=> 244, 1953=> -266, 1954=> 2600, 1955=> 3168, 1956=> 3218,
1957=> 3366, 1958=> 3300, 1959=> 3483, 1960=> 2386, 1961=> 3015,
1962=> 2090, 1963=> 2090, 1964=> 2264, 1965=> 2370, 1966=> 2185,
1967=> 2144, 1968=> 1526, 1971=> -393, 1972=> -430, 1973=> -445,
1974=> -543, 1975=> -393, 1980=> 300, 1981=> 490, 1982=> 400,
1983=> 445, 1984=> 393, 1987=>-1530, 1988=>-1600, 1990=> -362,
1991=> -366, 1992=> -400, 1993=> -449, 1994=> -321, 1995=> -344,
1999=> 356, 2000=> 480, 2001=> 483, 2002=> 504, 2003=> 294,
2007=> -206, 2008=> -314, 2009=> -466, 2010=> -416, 2011=> -457,
2012=> -313, 2018=> 347, 2020=> 257, 2021=> 351, 2022=> 159,
2023=> 177, 2026=> -134, 2027=> -340, 2028=> -382, 2029=> -320,
2030=> -470, 2031=> -370, 2032=> -373, 2036=> 349, 2037=> 523,
);
$addttime = array
(
1919=> array(14=>-160), 1939=> array(10=> -508),
1953=> array( 0=> 220), 1954=> array( 1=>-2973),
1982=> array(18=> 241), 1988=> array(13=>-2455),
2013=> array( 6=> 356), 2031=> array(20=> 411),
2023=> array( 0=> 399, 11=>-571),
);
return array($addstime[$year],$addttime[$year]);
}
## get the 24 solar terms, 1902 ~ 2037
##
## [usage]
## - array solar::terms(int year [, int smoon [, int length [, array &sun]]] )
##
function &terms($year=0, $smoon=1, $length=12, $sun=array())
{
$year = (int)$year;
$sun = array();
$smoon = (int)$smoon;
$length = (int)$length;
$times = array();
if(!$year) $year = date('Y');
if($year<1902 || $year>2037)
{
echo "\n".'error: invalid input '.$year.
', 1902 <= year <= 2037'."\n";
return -1;
}
list($hterms,$tterms) = solar::gterms();
list($addstime,$addttime) = solar::tterms($year);
## mktime(7+9,36,19-64,3,20,2000), 2000-03-20 16:35:15(KST)
##
$start = __SOLAR_START__; // start base unix timestamp
$tyear = __SOLAR_TYEAR__; // tropicalyear to seconds
$byear = __SOLAR_BYEAR__; // start base year
$start += ($year - $byear) * $tyear;
if($length < -12) $length = -12;
else if($length > 12) $length = 12;
$smoon = solar::moon2valid($smoon);
$emoon = solar::moon2valid($smoon+$length);
$sidx = (min($smoon,$emoon) - 1) * 2;
$eidx = ((max($smoon,$emoon) - 1) * 2) + 1;
for($i=$sidx; $i<=$eidx; $i++)
{
$time = $start + $tterms[$i];
list(,$atime) = solar::sunl($time,FALSE);
$time += $atime + $addstime + $addttime[$i]; // re-fixed
$terms[date('nd',$time)] = &$hterms[$i];
$times[] = $time; // fixed utime
}
## for detail information
##
if(func_num_args() > 3)
{
$i = $sidx;
foreach($times AS $time)
{
$sun[$i] = solar::sun($time,FALSE);
$sun[$i]['_avgdate'] =
gmdate('D, d M Y H:i:s T',$start+$tterms[$i]);
$sun[$i]['_name'] = &$hterms[$i];
$i++;
}
}
unset($times);
return $terms; // array
}
} // end of class
/*** example ***
$sun = array();
$terms = solar::terms(date('Y'),1,12,&$sun);
print_r($terms);
print_r($sun);
print_r(solar::sun(time()));
echo solar::today()."\n";
echo solar::solar(mktime(0,0,0,3,20))."\n";
echo solar::solar(mktime(0,0,0,3,21))."\n";
echo solar::solar(mktime(0,0,0,3,22))."\n";
echo "\n\n";
print_r(solar::terms(2023));
***/
?>
<?php
##
## array sort test
##########################################
require_once '_lib/class.solar.ph';
echo "<P><H2>24 절기 - 24 solar terms</H2>\n";
if($_GET['view'])
{
echo "<A HREF='$_SERVER[PHP_SELF]'>소스닫기</A><HR>\n";
highlight_file(basename($_SERVER[PHP_SELF]));
return;
}
echo "<A HREF='$_SERVER[PHP_SELF]?view=1'>소스보기</A><HR>\n";
echo '<PRE>'."\n";
?>
solar object -- get sun position or 24 solar terms
[author]
- Chilbong Kim, < san2(at)linuxchannel.net >
- http://linuxchannel.net/
[근사식에 대한 신뢰] 1902 ~ 2000 년
- 표준편차 : 1289.7736 = 21.5 분
- 평균오차 : +817.57409541246 = +13.6 분
- 최대오차 : +4102.7340(68.4 분), -4347.2395(72.5 분)
[근사식으로 계산한 24절기 실제 오차] 1902 ~ 2037 년
- 표준편차 : 1122.1921 = 18.7 분
- 평균오차 : +686.08382175161 = +11.4 분
- 최대오차 : +4297.252300024(71.6 분), -4278.048699975(71.3 분)
- 최소오차 : +0.16999998688698(0초)
[근사식 + 년도 보정으로 계산한 24절기 실제 오차] 1902 ~ 2037 년
- 표준편차 : 450.8534 = 7.5 분
- 평균오차 : +305.38638890903 = 5.0 분
- 최대오차 : +3028.2343000174 = 50.5 분, -1982.9391000271 = 33.1 분
- 최소오차 : +0.0085000991821289 = 0 초
<?php
list($year,$moon) = preg_split('/\s+/',date('Y n'));
$today = solar::today();
$tmoon = solar::terms($year,$moon,0);
$sun = solar::sun(time());
$suns = array();
$tterms = solar::terms($year,1,12,&$suns);
echo '<H3>년도 : '.$year.' 년</H3><P>'."\n";
echo '오늘 : '.$today.'<P>'."\n";
echo '이번달 : '.$year.' 년 '.$moon.' 월'."\n";
print_r($tmoon);
echo "\n\n";
echo '현재시각의 태양의 위치: '."\n";
print_r($sun);
echo "\n\n";
print_r($tterms);
echo "\n\n";
print_r($suns);
echo '</PRE>'."\n";
?>



댓글을 달아 주세요