## - http://linuxchannel.net/ ## ## [changes] ## - 2024.07.30 : calendar::_todate() errata _tmpm ## - 2021.06.08 : calendar::date("l") bug fixed ## - 2020.01.13 : polar() to simple ## - 2018.08.12 : tojd0() function name bug fixed ## - 2018.08.11 : (int) to (float) ## - 2018.07.31 : calendar::_todate() ## - 2018.07.28 : bug to delete san2@2018.07.28 ## - 2016.04.07 : date('N') ## - 2012.01.12 : add find_nw_in_month(), current_us_dst() ## - 2012.01.07 : support auto Julian calendar(date < 1582-10-15), _getjd(), _todate() ## - 2012.01.05 : add deltaT() ## - 2011.12.26 : add more utils ## - 2011.11.13 : some add/moved utils and added location_kr() ## - 2011.04.29 : comment patch(UT = TT - delta T) ## - 2011.04.24 : bug fixed, calendar::date('D') ## - 2010.05.20 : bug fixed, calendar::date('W') of ISO-8601 ## - 2010.05.19 : added calendar::date('J'), is a JD ## - 2010.05.18 : support calendar::date('I'), DST(daylight saving time) and all support of date() format. ## - 2009.06.08 : some ## - 2007.07.28 : support win32 PHP4(on Microsoft Windows) and Unix ## - 2005.04.12 : new build ## ## [valid date] ## - unix timestamp base: 1902-01-01 00:00:00 <= date <= 2037-12-31 23:59:59 (guess) ## - JD(Julian Day) base: JD 0.0 == BC 4713-01-01 12:00 UTC <= Gregorian date <= AD 9999 (guess) ## ## [download & online source view] ## - http://ftp.linuxchannel.net/devel/php_calendar/ ## ## [demo] ## - http://linuxchannel.net/gaggle/calendar.php // yet ## ## [references] ## - http://www.linuxchannel.net/docs/solar-24terms.txt ## - http://www.linuxchannel.net/docs/lunar.txt ## - http://www.merlyn.demon.co.uk/ // Astronomy and Astronautics ## - http://www.boogle.com/info/cal-overview.html ## - http://star-www.st-and.ac.uk/~fv/webnotes/index.html // Positional Astronomy ## - http://www.jgiesen.de/astro/astroJS/sunriseJS/index.htm // in rsTL.js ## - http://bodmas.org/astronomy/riset.html // same as rsTL.js ## - http://eclipse.gsfc.nasa.gov/SEhelp/deltatpoly2004.html // deltaT ## - http://blueedu.dothome.co.kr/xe/index.php?mid=astro&category=190&document_srl=11131 // deltaT ## - http://www.moshier.net/ deltaT from aa200c.zip: JPL ephemeris reader ## ## [julian date] -- this program ## input date time => return JD => return date time ## 1582-10-03 00:00 UTC => 2299158.5 => 1582-10-03 00:00 Julian date ## 1582-10-04 00:00 UTC => 2299159.5 => 1582-10-04 00:00 Julian date ## 1582-10-05 00:00 UTC => 2299160.5 => 1582-10-15 00:00 - ## 1582-10-06 00:00 UTC => 2299161.5 => 1582-10-16 00:00 - ## 1582-10-07 00:00 UTC => 2299162.5 => 1582-10-17 00:00 - ## 1582-10-08 00:00 UTC => 2299163.5 => 1582-10-18 00:00 - ## 1582-10-09 00:00 UTC => 2299164.5 => 1582-10-19 00:00 - ## 1582-10-10 00:00 UTC => 2299165.5 => 1582-10-20 00:00 - ## 1582-10-11 00:00 UTC => 2299166.5 => 1582-10-21 00:00 - ## 1582-10-12 00:00 UTC => 2299167.5 => 1582-10-22 00:00 - ## 1582-10-13 00:00 UTC => 2299168.5 => 1582-10-23 00:00 - ## 1582-10-14 00:00 UTC => 2299169.5 => 1582-10-24 00:00 - ## 1582-10-15 00:00 UTC => 2299160.5 => 1582-10-15 00:00 Gregorian date ## 1582-10-16 00:00 UTC => 2299161.5 => 1582-10-16 00:00 Gregorian date ## ## [time format] ## - UT = TT - dT ## - DT = in korean 'yeok-hak-si' ## - TDT(Terrestrial Dynamical Time) = DT(Dynamical Time) = TT(Terrestrial Time) ## - local = time(),date() ## - UT = gmtime(),gmdate() or local-time_offset ## - TT = UT + dT // use the astro caculating ## - JD <-> UT <-> GST <-> LST ## <-------------> ## <-------------> ## <--------------------> ## - jd2ut(JD,-time_offset) <-> ut2jd(ut,+time_offset) ## - ut2gst(ut) <-> gst2ut(gst) ## - gst2lst(gst,+lon_offset) <-> lst2gst(lst,-lon_offset) ## ## [float] ## - 1 second = 1/86400 = 0.000 011 574 074 074 074 = %.8f // Sufficient ## - 1 arcsec = 1/3600 = 0.000 277 78 = %.8f // Sufficient ## ## [JD/TT] ## ---------------------------------------------------------------------------------------- ## JD (not TT) JD or TT TT base ## ---------------------------------------------------------------------------------------- ## _todate($JD, $_timezone=NULL) jd2jd0($JD,$_timezone=NULL) tt2j2000t($TT) ## gmdate($format,$JD=NULL) tojd0($JD, $_timezone=NULL) _jd2j2000t($JD) ## date($format,$JD=NULL,$_timezone=NULL) jd0($JD, $_timezone=NULL) ecliptice($t=0) ## jd2lst($JD, $lon=0) - tt2ecliptice($TT) ## deltaT($Y='', $JD=NULL) - _jd2ecliptice($JD) ## - - psi($t=0) ## - - eps($t=0) ## ---------------------------------------------------------------------------------------- ## ## [compare 1. PHP4(win32) internal functions VS this method(object)] ## - time() ( mkjd() ) ## - date() _date(utime) // private, base on unix timestamp, BC 4313 ~ AD 9999(guess) ## - gmdate() _gmdate(utime) // private ## - mktime() _mktime() // private, support native value, BC 4313 ~ AD 9999(guess) ## - gmmktime() _gmmktime() // private ## ## [compare 2. PHP4(win32) calendar module VS this method(object)] ## - gregoriantojd() mkjd(),gmmkjd() // public, support hour, minute, seconds, BC 4313 ~ AD 9999(guess) ## - jdtogregorian() date(JD) // public, same as PHP `date()', but JD base ## gmdate(JD) // public, JD base ## - jddayofweek() jddayofweek(JD) // public, similar ## - cal_days_in_month() days_in_month() // public, similar ## - unixtojd() _utime2jd() // private, same above ## - jdtounix() _jd2utime() // private, same above ## ## [usage] -- see that last row of this source ## $jd = calendar::mkjd(23,59,59,12,31,1901); ## echo calendar::date('Y-m-d H:i:s T',$jd); ## @error_reporting(E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED); if(!defined('__TIMEZONE__')) define('__TIMEZONE__',date('Z')/3600); // system timezone for hours class calendar { ## private, get Julian day -- same as gregoriantojd() ## ## http://en.wikipedia.org/wiki/Julian_day ## http://ko.wikipedia.org/wiki/%EC%9C%A8%EB%A6%AC%EC%9A%B0%EC%8A%A4%EC%9D%BC ## ftp://ssd.jpl.nasa.gov/pub/eph/export/C-versions/hoffman/ ## http://blog.jidolstar.com/482 ## http://geekswithblogs.net/bosuch/archive/2011/05/13/determining-julian-date-in-c-or-java--android.aspx ## ## Julian date ## JD 0.0 == BC 4713-01-01 12:00 UTC == -4712-01-01 12:00:00 UTC ## ## input: local date time or unix timestamp ## $_timezone: input date timezone ## ## return: JD (UTC base) ## function &_getjd($Y, $M=1, $D=1, $H=21, $I=0, $S=0, $_timezone=NULL) { ## delta T ## //$dT = 64/86400; // is J2000.0 delta 'T', TT = UT + dT ## timezone ## if($_timezone === NULL) $_timezone = __TIMEZONE__; // system timezone for hours ## check arguments ## if(func_num_args() < 3) // $Y is local unix_timestamp { list($Y,$M,$D,$H,$I,$S) = explode(' ',calendar::_date('Y n j G i s',$Y)); } // local date time if($M < 3) { $M += 12; $Y--; } ## auto change to julian date ## $isjulian = sprintf('%d%02d%02d',$Y,$M,$D); $D += ($H/24.0) + ($I/1440.0) + ($S/86400.0); $A = floor($Y/100.0); // excel INT() == floor() != (int) $B = ($isjulian<15821015) ? 0 : (2.0 - $A + floor($A/4.0)); // juliantojd() $B = 0 $JD = floor(365.25*($Y+4716.0)) + floor(30.6001*($M+1.0)) + $D + $B - 1524.5; ## force local time to UTC ## $JD -= $_timezone/24; ## change to TT ## //$JD += $dT; // UT = TT - dT, do not plus $S or $JD of sprintf() internal $JD = round($JD, 8); $D = sprintf('%.8f', $JD-2451545.0); // float, number of days $J = sprintf('%.4f', 2000.0+($D/365.25)); // // Jxxxx.xxxx format $T = sprintf('%.8f', $D/36525.0); // // Julian century return array($JD,$J,$D,$T); // JD (UTC base) } ## private, get JD(julian day) from unix timestamp -- same as unixtojd() ## ## 1970-01-01 00:00:00 UTC == 2440587.5 JD == J1970.0 ## ## display date: KST = GMT + 9h ## numberic: mktime() = gmmktime() - 9h ## ## input: utime (local time) ## return: JD (UTC base) ## function &_utime2jd($utime) { return round($utime/86400, 8) + 2440587.5; // float } ## private, get unix timestamp from JD -- same as jdtounix() ## ## 1970-01-01 00:00:00 UTC == 2440587.5 JD == J1970.0 ## 1970-01-01 00:00:00 UTC == 1970-01-01 09:00:00 KST == 0 unix timestamp ## date(0) == auto change to local date time ## ## input: JD (UTC base) ## return: utime (from J1970.0) ## function &_jd2utime($JD) { $D = $JD - 2440587.5; // shift to J1970.0 $utime = round($D * 86400); return $utime; } ## private, check datetime that there is null or not null ## ## display date: KST = GMT + 9h ## numberic: mktime() = gmmktime() - 9h ## ## return: local date time ## function &__check_datetime($argc, &$Y, &$M, &$D, &$H, &$I, &$S, $_timezone) { if($argc >= 6) return TRUE; list($Y,$_M,$_D,$_H,$_I,$_S) = explode(' ',gmdate('Y n j G i s',time()+$_timezone*3600)); if($argc < 5) $D = $_D; if($argc < 4) $M = $_M; if($argc < 3) $S = $_S; if($argc < 2) $I = $_I; if($argc < 1) $H = $_H; } ## public, make JD -- match to mktime() ## ## Julian date ## JD 0.0 == BC 4713-01-01 12:00 UTC == -4712-01-01 12:00:00 UTC ~ AD 9999 ## function &mkjd($H=21, $I=0, $S=0, $M=1, $D=1, $Y=NULL, $_timezone=NULL) { if($_timezone === NULL) $_timezone = __TIMEZONE__; calendar::__check_datetime(func_num_args(),$Y,$M,$D,$H,$I,$S,$_timezone); list($JD) = calendar::_getjd($Y,$M,$D,$H,(int)$I,(int)$S,$_timezone); return $JD; // folat, JD (UTC base) } ## private, get unix timestamp from date -- same as mktime() ## ## valid date: 1902-01-01 00:00:00 ZONE <= date <= 2037-12-31 23:59:59 ZONE ## function &_mktime($H=0, $I=0, $S=0, $M=1, $D=1, $Y=NULL, $_timezone=NULL) { if($_timezone === NULL) $_timezone = __TIMEZONE__; ## bug to delete san2@2018.07.28 //if($Y>1970 && $Y<2038) return gmmktime($H,$I,$S,$M,$D,$Y)+($_timezone*3600); // local utime calendar::__check_datetime(func_num_args(),$Y,$M,$D,$H,$I,$S,$_timezone); $JD = calendar::mkjd($H,$I,$S,$M,$D,$Y,$_timezone); $utime = calendar::_jd2utime($JD); return $utime; // float, local utime } function &gmmkjd($H=0, $I=0, $S=0, $M=1, $D=1, $Y=NULL) // input date is UTC base { return calendar::mkjd($H,$I,$S,$M,$D,$Y,0); } function &_gmmktime($H=0, $I=0, $S=0, $M=1, $D=1, $Y=NULL) { return calendar::_mktime($H,$I,$S,$M,$D,$Y,0); } function &_gmdate($format, $utime=NULL) { return calendar::_date($format,$utime,0); } function &gmdate($format, $JD=NULL) { return calendar::date($format,$JD,0); } ## private, get date(gregorian) from JD -- same as jdtogregorian() ## ## input: JD (UTC base, not TT) ## return: local date time ## function &_todate($JD, $_timezone=NULL) { static $_months = array(31,0,31,30,31,30,31,31,30,31,30,31); // patch san2@2018.07.31 ## change TT to UT ## //$JD -= 64/86400; // is J2000.0 delta 'T', UT = TT - dT, patch san2@2007.07.28 ## change UT to local time ## if($_timezone === NULL) $_timezone = __TIMEZONE__; $JD += $_timezone/24; // JD to local zone(JD) $JD = round($JD+0.00000001, 8); // round-off error patch, by san2@2024.08.07 $T = $JD + 0.5; // shift to 00:00:00 $Z = floor($T); $W = floor(($Z-1867216.25) / 36524.25); // for gregorian $X = floor($W / 4); // for gregorian $A = ($Z<2299161.0) ? $Z : floor($Z+1+$W-$X); // is julian ? Z : gregorian $B = floor($A + 1524.0); $C = floor(($B-122.1) / 365.25); $D = floor(365.25 * $C); $E = floor(($B-$D) / 30.6001); $_d = $B - $D - floor(30.6001*$E); $_m = ($E<14) ? ($E-1) : ($E-13); $_y = ($_m>2) ? ($C-4716) : ($C-4715); /* $_U = $T - $Z; // flat, it's a UT 00:00 ~ 23:59:59 $_U = $_U * 24.0; // to hours $_h = (int)$_U; $_U = ($_U - $_h) * 60.0; // to minutes $_i = (int)$_U; $_U = ($_U - $_i) * 60.0; // to seconds $_s = (int)($_U + 0.001); // patch for round-off error, by san2@2012.01.10 */ $_U = round(($T-$Z) * 86400); // flat, it's a UT 00:00 ~ 23:59:59 $_h = floor($_U / 3600); $_i = floor(($_U % 3600) / 60); $_s = $_U % 60; /* ## patch san2@2012.02.19 ## if($_s > 59) { $_s -= 60; $_i++; if($_i > 59) { $_i -= 60; $_h++; if($_h > 23) { $_h -= 24; $_d++; ## patch san2@2018.07.31 ## $_tmpm = $_months[$_m-1]; if($_m == 2) { if($_d > 28) { if(calendar::isleap($_y)) { if($_d > 29) { $_d -= 29; $_m++; } } else { $_d -= 28; $_m++; } } } else if($_d > $_tmpm) { $_d -= $_tmpm; $_m++; if($_m > 12) { $_m -= 12; $_y++; } } } } } */ return array($_y,$_m,$_d,$_h,$_i,$_s); } ## private, same as `date()' function, base on unix timestamp(support Microsoft Windows PHP4) ## ## display date: KST = GMT + 9h ## numberic: mktime() = gmmktime() - 9h ## ## return: local date time ## function &_date($format, $utime=NULL, $_timezone=NULL) { if($utime === NULL) $utime = time(); // local utime if($_timezone === NULL) $_timezone = __TIMEZONE__; ## bug to delete san2@2018.07.28 //if($utime>=0 && $utime<2145884400) return gmdate($format,($utime+$_timezone*3600)); // local date time $JD = calendar::_utime2jd($utime); $str = calendar::date($format,$JD,$_timezone); // local date time return $str; // local date time } ## public, same as `date()' function, but base on JD by UT(delta T) ## ## valid JD: JD 0.0 == BC 4713-01-01 12:00 UTC == -4712-01-01 12:00:00 UTC ~ AD 9999 ## function &date($format, $JD=NULL, $_timezone=NULL) { static $_weeks = array('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'); static $_months = array('January','February','March','April','May','June','July','August', 'September','Octorber','November','December'); static $_ordinals = array(1=>'st',21=>'st',31=>'st',2=>'nd',22=>'nd',3=>'rd',23=>'rd'); if($_timezone === NULL) { $_timezone = __TIMEZONE__; $_dolocaldate = TRUE; } else { $_dolocaldate = FALSE; } $_timezonemark = $_timezone<0 ? '-' : '+'; if(func_num_args()<2 || $JD===NULL) $JD = calendar::mkjd(); // current JD(UT) if(!$format || is_array($format)) return calendar::_todate($JD,$_timezone); // array list($Y,$M,$D,$H,$I,$S) = calendar::_todate($JD,$_timezone); ## get DST(daylight saving time), patch san2@2010.05.19 ## http://www.alpheratz.net/php/RiseSetPHP // cf ## if($Y<1916 || $Y>2037 || !$_dolocaldate) { $_DST = 0; $_T = 'GMT'.$_timezonemark.$_timezone.'H'; // Timezone abbreviation } else { list($_DST,$_T) = explode(' ',date('I T',mktime(12,0,0,$M,$D,$Y))); } ## patch san2@2010.05.19 ## if($Y>1970 && $Y<2038) $_U = mktime($H,$I,$S,$M,$D,$Y); else $_U = calendar::_jd2utime($JD); $_Y = sprintf('%d',$Y); // not %04d $_M = sprintf('%02d',$M); $_D = sprintf('%02d',$D); $_H = sprintf('%02d',$H); $_I = sprintf('%02d',$I); $_S = sprintf('%02d',$S); $_Z = $_timezone*3600; // seconds $_O = $_timezonemark.gmdate('Hi',$_Z); $_w = calendar::jddayofweek($JD + ($_timezone/24)); // JD apply to local TimeZone $_W = calendar::weeknumber($Y,$M,$D); // ISO-8601 $_R = substr($_weeks[$_w],0,3).", $_D ".substr($_months[$M-1],0,3)." $H:$I:$S $_O"; $_P = substr($_O,0,3).':'.substr($_O,-2); $_C = "${_Y}-${_M}-${_D}T${_H}:${_I}:${_S}${_P}"; $_N = ($_w == 0) ? 7 : $_w; // patch san2@2016.04.07 $_o = ($M==12 && $_W==1) ? $Y+1 : (($M==1 && $_W>=52) ? $Y-1 : $Y); $r = ''; $nextskip = FALSE; $l = strlen($format); for($i=0; $i<$l; $i++) { $char = $format[$i]; if(!trim($char)) { $r .= $char; continue; } if($nextskip) { $r .= $char; $nextskip = FALSE; continue; } // patch san2@2010.05.19 if($char == '\\') { $nextskip = TRUE; continue; } else $nextskip = FALSE; switch($char) { case 'a': $r .= ($H<12) ? 'am' : 'pm'; break; case 'A': $r .= ($H<12) ? 'AM' : 'PM'; break; case 'B': $r .= calendar::itime($H,$I,$S,$_timezone); break; case 'c': $r .= $_C; break; // ISO 8601 date (added in PHP5) case 'd': $r .= $_D; break; case 'D': $r .= substr($_weeks[$_w],0,3); break; case 'F': $r .= $_months[$M-1]; break; case 'g': $r .= (($H-1) % 12) + 1; break; case 'G': $r .= $H; break; case 'h': $r .= sprintf('%02d',(($H-1)%12)+1); break; case 'H': $r .= $_H; break; case 'i': $r .= $_I; break; case 'I': $r .= $_DST; break; case 'j': $r .= $D; break; case 'J': $r .= $JD; break; case 'l': $r .= $_weeks[$_w]; break; case 'L': $r .= calendar::isleap($Y); break; case 'm': $r .= $_M; break; case 'M': $r .= substr($_months[$M-1],0,3); break; case 'n': $r .= $M; break; case 'N': $r .= $_N; break; // ISO-8601, day of the week, 1(Monday) ~ 7(Sunday) case 'o': $r .= $_o; break; // ISO-8601 year number case 'O': $r .= $_O; break; case 'P': $r .= $_P; break; case 'r': $r .= $_R; break; case 's': $r .= $_S; break; case 'S': $r .= $_ordinals[$D] ? $_ordinals[$D] : 'th'; break; case 't': $r .= calendar::days_in_month($Y,$M); break; case 'T': $r .= $_T; break; case 'u': $r .= date('u'); break; case 'U': $r .= $_U; break; case 'w': $r .= $_w; break; // JD to local zone case 'W': $r .= sprintf('%02d',$_W); break; // ISO-8601 case 'y': $r .= substr($_Y,-2); break; case 'Y': $r .= $_Y; break; // patch san2@2018.07.31 case 'z': $r .= calendar::dayofyear($Y,$M,$D); break; // starting from 0 case 'Z': $r .= $_Z; break; // KST zone +9H, in seconds default : $r .= $char; break; } } return $r; // string } ## public, get leap year ## ## #define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0) ## ## +-- 4*Y ! // normal ------------------ FALSE ## `-- 4*Y ## |-- 100*Y ! // leap ------------- TRUE ## `-- 100*Y ## |-- 400*Y ! // normal ------ FALSE ## `-- 400*Y // leap -------- TRUE ## ## but, 4000*Y is not normal year, is leap year ## http://user.chollian.net/~kimdbin/re/leap_year.html ## function &isleap($year) { ## for julian calendar ## if($year < 1582) return ($year%4) ? FALSE : TRUE; // for julian calendar ## for gregorian calendar ## if($year % 4) return FALSE; else if($year % 100) return TRUE; else if($year % 400) return FALSE; return TRUE; // else 400*Y } ## public, get week idx ## ## 0(sun), 1(mon), 2(tue), 3(wed), 4(thu), 5(fri), 6(sat) ## function &jddayofweek($JD) { return floor($JD+1.5) % 7; // integer } function &dayofyear($Y, $M, $D) { list($JDS) = calendar::_getjd($Y,1,1,12,0,0,0); list($JDE) = calendar::_getjd($Y,$M,$D,12,0,0,0); return (int)($JDE - $JDS); // starting from 0 } ## ISO-8601, start on Monday ## function &weeknumber_m($Y, $M, $D) { list($JD) = calendar::_getjd($Y,1,1,12,0,0,0); $widx = calendar::jddayofweek($JD); $days = calendar::dayofyear($Y,$M,$D); $midx = ($widx==0) ? 7 : $widx; // to ISO-8601 $days += ($midx>1) ? ($midx-7-1) : 0; $n = ceil($days/7); if($n >= 52) // last week { list($JD) = calendar::_getjd($Y,12,31,12,0,0,0); $lidx = calendar::jddayofweek($JD); if($widx>0 && $lidx>0) $n = 1; } else if($n <= 1) // first week { list($JD) = calendar::_getjd($Y-1,1,1,12,0,0,0); $widx = calendar::jddayofweek($JD); $n = ($widx>1) ? 52 : 53; } return $n; // integer } ## ISO-8601, start on Monday ## patch san2@2010.05.20 ## function &weeknumber($Y, $M, $D) { list($JD) = calendar::_getjd($Y,1,1,12,0,0,0); $widx = calendar::jddayofweek($JD) - 1; $days = calendar::dayofyear($Y,$M,$D); $midx = ($widx<0) ? 6 : $widx; $days = ($midx<4) ? ($days+$midx) : ($days+$midx-7); $n = floor($days/7) + 1; if($n == 0) // ok, first week or last of preious year { list($JD) = calendar::_getjd($Y-1,1,1,12,0,0,0); $widx = calendar::jddayofweek($JD); $n = ($widx>4) ? 52 : 53; } else if($n > 52) // last week or first week of next year { list($JD) = calendar::_getjd($Y,12,31,12,0,0,0); $widx = calendar::jddayofweek($JD); if($widx>0 && $widx<4) $n = 1; // Monday ~ Wednesday } return $n; // integer } ## public, get swatch internet time, base BMT = UTC + 1 ## same as date('B') ## function &itime($H, $I, $S, $_timezone) { $B = ($H-$_timezone+1)*41.666 + $I*0.6944 + $S*0.01157; $B = ($B>0) ? $B : $B+1000.0; return sprintf('%03d',$B); } ## public ## function &days_in_month($year, $month) { static $_months = array(31,0,31,30,31,30,31,31,30,31,30,31); if($year.$month == 158210) return 21; // 1582-10-01 ~ 31 == 21 days $n = $_months[$month-1]; $n = $n ? $n : (calendar::isleap($year) ? 29 : 28); return $n; // integer } ## find a day of the n'th week in month ## ## $n = 1'th week, 2nd week, ... 5'th week, Sunday is the start of a week ## $w = Sunday(0), Monday(1), ... Saturday(6) ## ## default) find a day of the first week of sunday in this month ## function &find_nw_in_month($n=1, $w=0, $month=NULL, $year=NULL) { if($n<1 || $n>5) $n = 1; if($w<0 || $w>6) $w = 0; if($month===NULL || $year===NULL) { list($_y,$_m) = explode(' ',date('Y n')); if($month === NULL) $month = $_m; if($year === NULL) $year = $_y; } list($JD) = calendar::_getjd($year,$month,1,12,0,0,0); list($t,$week) = explode(' ',calendar::date('t w',$JD)); $sunday = ($week==0) ? 1 : (8-$week); // day of first sunday $day = ($sunday+$w) + ($n-1)*7; $day -= ($day>$t) ? $t : 0; // next month if($year == 1582) { if($month==9 && $n==5 && $w>4) $day += 10; else if($month==10 && $n<3) $day += 10; else if($month==10 && $n==3 && $w==0) $day += 10; // 31 } return $day; } ## USA DST(daylight saving time) ## ## Asia/Seoul ## Asia/Tokyo ## Asia/Shanghai ## America/Los_Angeles ## function ¤t_us_dst() { $ctz = date_default_timezone_get(); date_default_timezone_set('America/Los_Angeles'); $dst = date('I'); // is DST ? date_default_timezone_set($ctz); return $dst; } ## this function does working ## ## USA 1986-2006, from first Sunday in April to the last Sunday in October ## USA 2007, from second Sunday in March to the first Sunday in November ## http://www.neoprogrammics.com/perpetual_calendar_algorithms/Daylight_Saving_Time_USA.php ## ## EU Since 1998, from the last Sunday in March to the last Sunday in October ## http://www.neoprogrammics.com/perpetual_calendar_algorithms/Summer_Time_EU.php ## function &_current_us_dst($_timezone=-8) { $ustime = time() - date('Z') + ($_timezone*3600); // gmmktime() == mktime() why? $stime = mktime(12,0,0,3,calendar::find_nw_in_month(2,0,3)); // second Sunday in March $etime = mktime(12,0,0,11,calendar::find_nw_in_month(1,0,11)); // first Sunday in November return ($ustime>$stime && $ustime<$etime) ? 1 : 0; } ## public ## function &month_info($year, $month) { if($year<1902 || $year>2037) { list($JD) = calendar::_getjd($year,$month,1,12,0,0,0); $term = calendar::days_in_month($year,$month); $week = calendar::jddayofweek($JD); // week idx $minfo = array($week,$term); } else { $utime = mktime(12,0,0,$month,1,$year); $minfo = explode(' ',date('w t',$utime)); } return $minfo; // array($week,$term) } ## [utils] ## ## deg ## deg2dms ## deg2dm ## deg2h ## deg2hms ## deg2hm ## h ## h2hms ## h2hm ## h2hm30 // add ## h2deg ## h2dms ## h2dm ## dms(dm) ## dms2deg ## dms2dm ## dms2h ## dms2hms ## dms2hm ## hms(hm) ## hms2h ## hms2hm ## hms2deg ## hms2dms ## hms2dm ## function °2dms($deg, $singed=FALSE) { if($singed) $singed = '+'; if($deg <0) { $singed = '-'; $deg = abs($deg); } $d = floor($deg); $deg = ($deg-$d) * 60; $m = floor($deg); $deg = ($deg-$m) * 60; $s = floor($deg); // not round() return $singed.sprintf('%02d %02d %02d',$d,$m,$s); } function °2dm($deg, $singed=FALSE) { if($singed) $singed = '+'; if($deg < 0) { $singed = '-'; $deg = abs($deg); } $d = floor($deg); $m = ($deg-$d) * 60; $m = round($m); // round if($m > 59) { $m -= 60; $d++; } return $singed.sprintf('%02d %02d',$d,$m); } function °2h($deg) { return ($deg/15); } function °2hms($deg, $singed=FALSE) { return calendar::deg2dms($deg/15,$singed); } function °2hm($deg, $singed=FALSE) { return calendar::deg2dm($deg/15,$singed); } function &h2hms($h) { return calendar::deg2dms($h); // match h to d } function &h2hm($h) { return str_replace(' ',':',calendar::deg2dm($h)); // match h to d } function &h2hm30($h) { $d = floor($h); $m = ($h-$d) * 60; $m = round($m); // round $k = floor($m/15); $k = ceil($k/2); $m = $k * 30; if($m > 59) { $m -= 60; $d++; } return sprintf('%02d:%02d',$d,$m); } function &h2deg($h) { return ($h*15); } function &h2dms($h) { return calendar::deg2dms($h*15); } function &h2dm($h) { return calendar::deg2dm($h*15); } function &dms2deg($dms, $f=8) { if(!is_array($dms) && preg_match('/^[\d.+-]+$/',$dms)) return sprintf("%.${f}f",$dms); if(is_array($dms)) list($d,$m,$s) = $dms; else { $dms = preg_replace('/[^\d.+-]+/',' ',trim($dms)); list($d,$m,$s) = explode(' ',$dms); } if(preg_match('/^-/',$d)) $deg = sprintf("%.${f}f",$d-$m/60-$s/3600); // -0 to < 0 else $deg = sprintf("%.${f}f",$d+$m/60+$s/3600); return $deg; } function &dms2dm($dms) { return calendar::deg2dm(calendar::dms2deg($dms)); } function &dms2h($dms) { return (calendar::dms2deg($dms) / 15); } function &dms2hms($dms) { return calendar::deg2hms(calendar::dms2deg($dms)); } function &dms2hm($dms) { return calendar::deg2hm(calendar::dms2deg($dms)); } function &hms2h($hms) { return calendar::dms2deg($hms); // match h to d } function &hms2hm($hms) { return str_replace(' ',':',calendar::dms2dm($hms)); // match h to d } function &hms2deg($hms) { return (calendar::dms2deg($hms) * 15); // match h to d and *15 } function &hms2dms($hms) { return calendar::deg2dms(calendar::hms2deg($hms)); } function &hms2dm($hms) { return calendar::deg2dm(calendar::hms2deg($hms)); } function &str2deg($str) { list($od,$om,$os,$td,$tm,$ts) = preg_split('/[^\d.+-]+/',trim($str)); if($ts != '') // 0 is not null { $r[0] = calendar::dms2deg("$od $om $os",2); $r[1] = calendar::dms2deg("$td $tm $ts",2); } else if($td != '') // 0 is not null { $r[0] = calendar::dms2deg("$od $om",2); $r[1] = calendar::dms2deg("$os $td",2); } else $r = array($od,$om); return $r; } ## 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 °2valid($deg) { $deg = ($deg<0) ? fmod($deg,360)+360.0 : fmod($deg,360); return $deg; } function &moon2valid($moon) { if($moon < 1) $moon = 1; else if($moon > 12) $moon = 12; return (int)$moon; } ## RA to valid ( 0 ~ 24) ## function &ra2valid($ra) { $ra = ($ra<0) ? fmod($ra,24.0)+24.0 : fmod($ra,24.0); return $ra; } ## HA valid (-12h to 12h) ## function &ha2valid($ha) { $ha = fmod($ha,24.0); $ha += ($ha>12.0) ? -24.0 : (($ha<-12.0) ? 24.0 : 0); return $ha; } ## alt/dec from South or North ## -90 < alt < +90 ## function &alt2valid($alt, $base='S') { $base = strtoupper($base); $alt = fmod($alt,360.0); $alt += ($alt<-180.0) ? 360.0 : (($alt>180.0) ? -360.0 : 0); if(abs($alt) < 90.0) return array($alt,$base); $alt = ($alt>0) ? (180.0-$alt) : (-180.0-$alt); $base = ($base=='S') ? 'N' : 'S'; // reverse return array($alt,$base); } function &jd2mjd($JD) { return ($JD - 2400000.5); } function &mjd2jd($MJD) { return ($MJD + 2400000.5); } ## JD to 00:00:00 UT (JD to 0.5) ## function &jd2jd0($JD, $_timezone=NULL) { if($_timezone === NULL) $_timezone = __TIMEZONE__; // system timezone for hours $offset = 0.5 - ($_timezone/24.0); $JD0 = floor($JD); // to noon $JD0 += (($JD-$JD0)<$offset) ? ($offset-1) : $offset; // PM ? (-1+0.5) : 0.5 return $JD0; } function &tojd0($JD, $_timezone=NULL) { return calendar::jd2jd0($JD,$_timezone); } function &jd0($JD, $_timezone=NULL) { return calendar::jd2jd0($JD,$_timezone); } ## note: TT base ## function &tt2j2000t($TT) { $t = ($TT-2451545.0) / 36525.0; // J2000.0 century return sprintf('%.12f',$t); // float } ## alias of tt2j2000t(TT) ## function &_jd2j2000t($JD) { return calendar::tt2j2000t($JD); } ## IAU2006 ## 84381".406 == 23 26' 21".406 ## 84381".406 - 46".836769 t - 0".0001831 t2 + 0".00200340 t3 - 0".000000576 t4 - 0".0000000434 t5 ## ## $t is TT base J2000.0 Julian Century ## function &_ecliptice($t=0) { $t2 = $t*$t; $t3 = $t*$t2; $e = 84381.406 - (46.836769*$t) - (0.0001831*$t2) + (0.00200340*$t3) - (0.000000576*$t2*$t2) - (0.0000000434*$t2*$t3); return sprintf('%.8f',$e/3600); // degrees } ## 84381.448" == 23 26' 21.448" at J2000.0 ## http://www.neoprogrammics.com/obliquity_of_the_ecliptic/ ## http://www.neoprogrammics.com/obliquity_of_the_ecliptic/Obliquity_Of_The_Ecliptic.php ## ## $t is TT base J2000.0 Julian Century ## function &ecliptice($t=0) { ## J. Laskar's Formula For The Mean Obliquity ## $u = $t/100; // ($JD-2451545.0)/3652500.0, 10000 Julian years from J2000.0 $u2 = $u*$u; $u3 = $u*$u2; $u4 = $u*$u3; $e = 84381.448 - (4680.93*$u) - (1.55*$u2) + (1999.25*$u3) - (51.38*$u4) - (249.67*$u2*$u3) - (39.05*$u3*$u3) + (7.12*$u3*$u4) + (27.87*$u4*$u4) + (5.79*$u4*$u5) + (2.45*$u5*$u5); $e /= 3600; // to degrees ## True Obliquity == e + eps ## $eps = calendar::eps($t); // degrees, $t is J2000.0 Julian century return sprintf('%.8f',$e+$eps); // degrees } ## TT base ## function &tt2ecliptice($TT) { return calendar::ecliptice(($TT-2451545.0)/36525.0); } ## JD is TT base ## function &_jd2ecliptice($JD) { return calendar::ecliptice(($JD-2451545.0)/36525.0); } ## delta psi ## ## Algorithm for computing the Nutation (Delta Psi) In Ecliptical Longitude ## http://www.neoprogrammics.com/nutations/dPsi_2000B_Algorithm_Guide.html ## ## true = mean + psi ## use in: lst, L(sun/moon) ## ## $t is TT base J2000.0 Julian Century ## function &psi($t=0) { $t2 = $t * $t; $t3 = $t * $t2; $t4 = $t * $t3; $L0 = (450160.398036 - 6962890.5431*$t + 7.4722*$t2 + 0.007702*$t3 - 0.00005939*$t4) / 3600.0; $L = deg2rad((485868.249036 + 1717915923.2178*$t + 31.8792*$t2 + 0.051635*$t3 - 0.00024470*$t4) / 3600.0); $LS = deg2rad((1287104.79305 + 129596581.0481*$t - 0.5532*$t2 + 0.000136*$t3 - 0.00001149*$t4) / 3600.0); $D = deg2rad((1072260.70369 + 1602961601.2090*$t - 6.3706*$t2 + 0.006593*$t3 - 0.00003169*$t4) / 3600.0); $F = deg2rad((335779.526232 + 1739527262.8478*$t - 12.7512*$t2 - 0.001037*$t3 + 0.00000417*$t4) / 3600.0); $OM = deg2rad($L0); $psi = (-172064161 - 174666*$t)*sin($OM) + 33386*cos($OM) + (-13170906 - 1675*$t)*sin(2*($F - $D + $OM)) - 13696*cos(2*($F - $D + $OM)) + (-2276413 - 234*$t)*sin(2*($F + $OM)) + 2796*cos(2*($F + $OM)) + (2074554 + 207*$t)*sin(2*$OM) - 698*cos(2*$OM) + (1475877 - 3633*$t)*sin($LS) + 11817*cos($LS) + (-516821 + 1226*$t)*sin($LS + 2*($F - $D + $OM)) - 524*cos($LS + 2*($F - $D + $OM)) + (711159 + 73*$t)*sin($L) - 872*cos($L) + (-387298 - 367*$t)*sin(2*$F + $OM) + 380*cos(2*$F + $OM) + (-301461 - 36*$t)*sin($L + 2*($F + $OM)) + 816*cos($L + 2*($F + $OM)) + (215829 - 494*$t)*sin(2*($F - $D + $OM) - $LS) + 111*cos(2*($F - $D + $OM) - $LS) + (128227 + 137*$t)*sin(2*($F - $D) + $OM) + 181*cos(2*($F - $D) + $OM) + (123457 + 11*$t)*sin(2*($F + $OM) - $L) + 19*cos(2*($F + $OM) - $L) + (156994 + 10*$t)*sin(2*$D - $L) - 168*cos(2*$D - $L) + (63110 + 63*$t)*sin($L + $OM) + 27*cos($L + $OM) + (-57976 - 63*$t)*sin($OM - $L) - 189*cos($OM - $L) + (-59641 - 11*$t)*sin(2*($F + $D + $OM) - $L) + 149*cos(2*($F + $D + $OM) - $L) + (-51613 - 42*$t)*sin($L + 2*$F + $OM) + 129*cos($L + 2*$F + $OM) + (45893 + 50*$t)*sin(2*($F - $L) + $OM) + 31*cos(2*($F - $L) + $OM) + (63384 + 11*$t)*sin(2*$D) - 150*cos(2*$D) + (-38571 - $t)*sin(2*($F + $D + $OM)) + 158*cos(2*($F + $D + $OM)) + 32481*sin(2*($F - $LS - $D + $OM)) - 47722*sin(2*($D - $L)) - 18*cos(2*($D - $L)) + (-31046 - $t)*sin(2*($L + $F + $OM)) + 131*cos(2*($L + $F + $OM)) + 28593*sin($L + 2*($F - $D + $OM)) - cos($L + 2*($F - $D + $OM)) + (20441 + 21*$t)*sin(2*$F + $OM - $L) + 10*cos(2*$F + $OM - $L) + 29243*sin(2*$L) - 74*cos(2*$L) + 25887*sin(2*$F) - 66*cos(2*$F) + (-14053 - 25*$t)*sin($LS + $OM) + 79*cos($LS + $OM) + (15164 + 10*$t)*sin(2*$D - $L + $OM) + 11*cos(2*$D - $L + $OM) + (-15794 + 72*$t)*sin(2*($LS + $F - $D + $OM)) - 16*cos(2*($LS + $F - $D + $OM)) + 21783*sin(2*($D - $F)) + 13*cos(2*($D - $F)) + (-12873 - 10*$t)*sin($L - 2*$D + $OM) - 37*cos($L - 2*$D + $OM) + (-12654 + 11*$t)*sin($OM - $LS) + 63*cos($OM - $LS) - 10204*sin(2*($F + $D) + $OM - $L) + 25*cos(2*($F + $D) + $OM - $L) + (16707 - 85*$t)*sin(2*$LS) - 10*cos(2*$LS) - 7691*sin($L + 2*($F + $D + $OM)) + 44*cos($L + 2*($F + $D + $OM)) - 11024*sin(2*($F - $L)) - 14*cos(2*($F - $L)) + (7566 - 21*$t)*sin($LS + 2*($F + $OM)) - 11*cos($LS + 2*($F + $OM)) + (-6637 - 11*$t)*sin(2*($F + $D) + $OM) + 25*cos(2*($F + $D) + $OM) + (-7141 + 21*$t)*sin(2*($F + $OM) - $LS) + 8*cos(2*($F + $OM) - $LS) + (-6302 - 11*$t)*sin(2*$D + $OM) + 2*cos(2*$D + $OM) + (5800 + 10*$t)*sin($L + 2*($F - $D) + $OM) + 2*cos($L + 2*($F - $D) + $OM) + 6443*sin(2*($L + $F - $D + $OM)) - 7*cos(2*($L + $F - $D + $OM)) + (-5774 - 11*$t)*sin(2*($D - $L) + $OM) - 15*cos(2*($D - $L) + $OM) - 5350*sin(2*($L + $F) + $OM) + 21*cos(2*($L + $F) + $OM) + (-4752 - 11*$t)*sin(2*($F - $D) + $OM - $LS) - 3*cos(2*($F - $D) + $OM - $LS) + (-4940 - 11*$t)*sin($OM - 2*$D) - 21*cos($OM - 2*$D) + 7350*sin(2*$D - $L - $LS) - 8*cos(2*$D - $L - $LS) + 4065*sin(2*($L - $D) + $OM) + 6*cos(2*($L - $D) + $OM) + 6579*sin($L + 2*$D) - 24*cos($L + 2*$D) + 3579*sin($LS + 2*($F - $D) + $OM) + 5*cos($LS + 2*($F - $D) + $OM) + 4725*sin($L - $LS) - 6*cos($L - $LS) - 3075*sin(2*($F + $OM - $L)) - 2*cos(2*($F + $OM - $L)) - 2904*sin(3*$L + 2*($F + $OM)) + 15*cos(3*$L + 2*($F + $OM)) + 4348*sin(2*$D - $LS) - 10*cos(2*$D - $LS) - 2878*sin($L - $LS + 2*($F + $OM)) + 8*cos($L - $LS + 2*($F + $OM)) - 4230*sin($D) + 5*cos($D) - 2819*sin(2*($F + $D + $OM) - $L - $LS) + 7*cos(2*($F + $D + $OM) - $L - $LS) - 4056*sin(2*$F - $L) + 5*cos(2*$F - $L) - 2647*sin(2*($F + $D + $OM) - $LS) + 11*cos(2*($F + $D + $OM) - $LS) - 2294*sin($OM - 2*$L) - 10*cos($OM - 2*$L) + 2481*sin($L + $LS + 2*($F + $OM)) - 7*cos($L + $LS + 2*($F + $OM)) + 2179*sin(2*$L + $OM) - 2*cos(2*$L + $OM) + 3276*sin($LS + $D - $L) + cos($LS + $D - $L) - 3389*sin($L + $LS) + 5*cos($L + $LS) + 3339*sin($L + 2*$F) - 13*cos($L + 2*$F) - 1987*sin(2*($F - $D) + $OM - $L) - 6*cos(2*($F - $D) + $OM - $L) - 1981*sin($L + 2*$OM) + 4026*sin($D - $L) - 353*cos($D - $L) + 1660*sin(2*$F + $D + 2*$OM) - 5*cos($D + 2*($F + $OM)) - 1521*sin(2*($F + 2*$D + $OM) - $L) + 9*cos(2*($F + 2*$D + $OM) - $L) + 1314*sin($LS + $D + $OM - $L) - 1283*sin(2*($F - $D - $LS) + $OM) - 1331*sin($L + 2*$F + 2*$D + $OM) + 8*cos($L + 2*($F + $D) + $OM) + 1383*sin(2*($F - $L + $D + $OM)) - 2*cos(2*($F - $L + $D + $OM)) + 1405*sin(2*$OM - $L) + 4*cos(2*$OM - $L) + 1290*sin($L + $LS + 2*($F - $D + $OM)); $psi /= 36000000000.0; // to grees return $psi; // float, degrees } ## delta epsilon ## ## Algorithm For computing the Nutation in Obliquity (Delta Epsilon) of the Ecliptic ## http://www.neoprogrammics.com/nutations/dEps_2000B_Algorithm_Guide.html ## http://www.neoprogrammics.com/obliquity_of_the_ecliptic/Obliquity_Of_The_Ecliptic.php ## ## true = mean + eps ## use in: eclipice, B(sun/moon) ## ## $t is TT base J2000.0 Julian Century ## function &eps($t=0) { $t2 = $t * $t; $t3 = $t * $t2; $t4 = $t * $t3; $L0 = (450160.398036 - 6962890.5431*$t + 7.4722*$t2 + 0.007702*$t3 - 0.00005939*$t4) / 3600.0; $L = deg2rad((485868.249036 + 1717915923.2178*$t + 31.8792*$t2 + 0.051635*$t3 - 0.00024470*$t4) / 3600.0); $LS = deg2rad((1287104.79305 + 129596581.0481*$t - 0.5532*$t2 + 0.000136*$t3 - 0.00001149*$t4) / 3600.0); $D = deg2rad((1072260.70369 + 1602961601.2090*$t - 6.3706*$t2 + 0.006593*$t3 - 0.00003169*$t4) / 3600.0); $F = deg2rad((335779.526232 + 1739527262.8478*$t - 12.7512*$t2 - 0.001037*$t3 + 0.00000417*$t4) / 3600.0); $OM = deg2rad($L0); $eps = (92052331 + 9086*$t)*cos($OM) + 15377*sin($OM) + (5730336 - 3015*$t)*cos(2*($F - $D + $OM)) - 4587*sin(2*($F - $D + $OM)) + (978459 - 485*$t)*cos(2*($F + $OM)) + 1374*sin(2*($F + $OM)) + (-897492 + 470*$t)*cos(2*$OM) - 291*sin(2*$OM) + (73871 - 184*$t)*cos($LS) - 1924*sin($LS) + (224386 - 677*$t)*cos($LS + 2*($F - $D + $OM)) - 174*sin($LS + 2*($F - $D + $OM)) - 6750*cos($L) + 358*sin($L) + (200728 + 18*$t)*cos(2*$F + $OM) + 318*sin(2*$F + $OM) + (129025 - 63*$t)*cos($L + 2*($F + $OM)) + 367*sin($L + 2*($F + $OM)) + (-95929 + 299*$t)*cos(2*($F - $D + $OM) - $LS) + 132*sin(2*($F - $D + $OM) - $LS) + (-68982 - 9*$t)*cos(2*($F - $D) + $OM) + 39*sin(2*($F - $D) + $OM) + (-53311 + 32*$t)*cos(2*($F + $OM) - $L) - 4*sin(2*($F + $OM) - $L) - 1235*cos(2*$D - $L) + 82*sin(2*$D - $L) - 33228*cos($L + $OM) - 9*sin($L + $OM) + 31429*cos($OM - $L) - 75*sin($OM - $L) + (25543 - 11*$t)*cos(2*($F + $D + $OM) - $L) + 66*sin(2*($F + $D + $OM) - $L) + 26366*cos($L + 2*$F + $OM) + 78*sin($L + 2*$F + $OM) + (-24236 - 10*$t)*cos(2*($F - $L) + $OM) + 20*sin(2*($F - $L) + $OM) - 1220*cos(2*$D) + 29*sin(2*$D) + (16452 - 11*$t)*cos(2*($F + $D + $OM)) + 68*sin(2*($F + $D + $OM)) - 13870*cos(2*($F - $LS - $D + $OM)) + 477*cos(2*($D - $L)) - 25*sin(2*($D - $L)) + (13238 - 11*$t)*cos(2*($L + $F + $OM)) + 59*sin(2*($L + $F + $OM)) + (-12338 + 10*$t)*cos($L + 2*($F - $D + $OM)) - 3*sin($L + 2*($F - $D + $OM)) - 10758*cos(2*$F + $OM - $L) - 3*sin(2*$F + $OM - $L) - 609*cos(2*$L) + 13*sin(2*$L) - 550*cos(2*$F) + 11*sin(2*$F) + (8551 - 2*$t)*cos($LS + $OM) - 45*sin($LS + $OM) - 8001*cos(2*$D + $OM - $L) - sin(2*$D + $OM - $L) + (6850 - 42*$t)*cos(2*($LS + $F - $D + $OM)) - 5*sin(2*($LS + $F - $D + $OM)) - 167*cos(2*($D - $F)) + 13*sin(2*($D - $F)) + 6953*cos($L - 2*$D + $OM) - 14*sin($L - 2*$D + $OM) + 6415*cos($OM - $LS) + 26*sin($OM - $LS) + 5222*cos(2*($F + $D) + $OM - $L) + 15*sin(2*($F + $D) + $OM - $L) + (168 - $t)*cos(2*$LS) + 10*sin(2*$LS) + 3268*cos($L + 2*($F + $D + $OM)) + 19*sin($L + 2*($F + $D + $OM)) + 104*cos(2*($F - $L)) + 2*sin(2*($F - $L)) - 3250*cos($LS + 2*($F + $OM)) - 5*sin($LS + 2*($F + $OM)) + 3353*cos(2*($F + $D) + $OM) + 14*sin(2*($F + $D) + $OM) + 3070*cos(2*($F + $OM) - $LS) + 4*sin(2*($F + $OM) - $LS) + 3272*cos(2*$D + $OM) + 4*sin(2*$D + $OM) - 3045*cos($L + 2*($F - $D) + $OM) - sin($L + 2*($F - $D) + $OM) - 2768*cos(2*($L + $F - $D + $OM)) - 4*sin(2*($L + $F - $D + $OM)) + 3041*cos(2*($D - $L) + $OM) - 5*sin(2*($D - $L) + $OM) + 2695*cos(2*($L + $F) + $OM) + 12*sin(2*($L + $F) + $OM) + 2719*cos(2*($F - $D) + $OM - $LS) - 3*sin(2*($F - $D) + $OM - $LS) + 2720*cos($OM - 2*$D) - 9*sin($OM - 2*$D) - 51*cos(2*$D - $L - $LS) + 4*sin(2*$D - $L - $LS) - 2206*cos(2*($L - $D) + $OM) + sin(2*($L - $D) + $OM) - 199*cos($L + 2*$D) + 2*sin($L + 2*$D) - 1900*cos($LS + 2*($F - $D) + $OM) + sin($LS + 2*($F - $D) + $OM) - 41*cos($L - $LS) + 3*sin($L - $LS) + 1313*cos(2*($F - $L + $OM)) - sin(2*($F - $L + $OM)) + 1233*cos(3*$L + 2*($F + $OM)) + 7*sin(3*$L + 2*($F + $OM)) - 81*cos(2*$D - $LS) + 2*sin(2*$D - $LS) + 1232*cos($L - $LS + 2*($F + $OM)) + 4*sin($L - $LS + 2*($F + $OM)) - 20*cos($D) - 2*sin($D) + 1207*cos(2*($F + $D + $OM) - $L - $LS) + 3*sin(2*($F + $D + $OM) - $L - $LS) + 40*cos(2*$F - $L) - 2*sin(2*$F - $L) + 1129*cos(2*($F + $D + $OM) - $LS) + 5*sin(2*($F + $D + $OM) - $LS) + 1266*cos($OM - 2*$L) - 4*sin($OM - 2*$L) - 1062*cos($L + $LS + 2*($F + $OM)) - 3*sin($L + $LS + 2*($F + $OM)) - 1129*cos(2*$L + $OM) - 2*sin(2*$L + $OM) - 9*cos($LS + $D - $L) + 35*cos($L + $LS) - 2*sin($L + $LS) - 107*cos($L + 2*$F) + sin($L + 2*$F) + 1073*cos(2*($F - $D) + $OM - $L) - 2*sin(2*($F - $D) + $OM - $L) + 854*cos($L + 2*$OM) - 553*cos($D - $L) - 139*sin($D - $L) - 710*cos(2*($F + $OM) + $D) - 2*sin(2*($F + $OM) + $D) + 647*cos(2*($F + 2*$D + $OM) - $L) + 4*sin(2*($F + 2*$D + $OM) - $L) - 700*cos($LS + $D + $OM - $L) + 672*cos(2*($F - $LS - $D) + $OM) + 663*cos($L + 2*($F + $D) + $OM) + 4*sin($L + 2*($F + $D) + $OM) - 594*cos(2*($F - $L + $D + $OM)) - 2*sin(2*($F - $L + $D + $OM)) - 610*cos(2*$OM - $L) + 2*sin(2*$OM - $L) - 556*cos($L + $LS + 2*($F - $D + $OM)); $eps /= 36000000000.0; // to degrees return $eps; // degrees, float } ## ec2eq(L, B, e=23.4595) to array(RA,dec) ## eq2ec(ra, dec, e=23.4594) to array(L,B) ## eq2ha(dec, lat, alt=0) to HA ## eq2alt(dec, lat, ha) to alt ## eq2az(dec, lat, ha) to AZ ## az2polar(az) to polar ## sin(dec) = sin(B)*cos(e) + cos(B)*sin(e)*sin(L) ## tan(RA) = (sin(L)*cos(e) - tan(B)*sin(e)) / cos(L) = x/y ## function &ec2eq($L, $B, $e=23.4395) { $L = deg2rad($L); $B = deg2rad($B); $e = deg2rad($e); $sindec = sin($B)*cos($e) + cos($B)*sin($e)*sin($L); $dec = rad2deg(asin($sindec)); $x = sin($L)*cos($e) - tan($B)*sin($e); $y = cos($L); $ra = rad2deg(atan2($x,$y)) / 15; $ra = ($ra<0) ? fmod($ra,24.0)+24.0 : fmod($ra,24.0); // ra valid, calendar::ra2valid($ra) return array($ra,$dec); } ## sin(B) = sin(dec)*cos(e) - cos(dec)*sin(e)*sin(RA) ## tan(L) = (sin(RA)*cos(e) + tan(dec)*sin(e)) / cos(RA) = x/y ## function &eq2ec($ra, $dec, $e=23.4395) { $ra = deg2rad($ra); // input ra is a degrees $dec = deg2rad($dec); $e = deg2rad($e); $sinb = sin($dec)*cos($e) - cos($dec)*sin($e)*sin($ra); $B = rad2deg(asin($sinb)); $x = sin($ra)*cos($e) + tan($dec)*sin($e); $y = cos($ra); $L = rad2deg(atan2($x,$y)); if($L < 0) $L += 360.0; return array($L,$B); } ## sin(h) = sin(d)*sin(La) + cos(d)*cos(La)*cos(Ha) ## function &eq2ha($dec, $lat, $alt=0) { $dec = deg2rad($dec); $lat = deg2rad($lat); $alt = deg2rad($alt); $x = sin($dec)*sin($lat) - sin($alt); $y = cos($dec)*cos($lat); $ha = (180 - rad2deg(acos($x/$y))) / 15; // to hour angle $ha = calendar::ha2valid($ha); return sprintf('%.8f',$ha); } ## sin(h) = sin(d)*sin(La) + cos(d)*cos(La)*cos(Ha) ## function &eq2alt($dec, $lat, $ha) { $dec = deg2rad($dec); $lat = deg2rad($lat); $ha = deg2rad($ha); // input ha is a degrees $sinh= sin($dec)*sin($lat) + cos($dec)*cos($lat)*cos($ha); $alt = rad2deg(asin($sinh)); return sprintf('%.8f',$alt); } ## Azimuth ## tan(A) = -cos(dec)*sin(Ha) / (sin(dec)*cos(lat) - cos(dec)*sin(lat)*cos(Ha)) ## function &eq2az($dec, $lat, $ha) { $dec = deg2rad($dec); $ha = deg2rad($ha); // input ha is a degrees $lat = deg2rad($lat); $x = -cos($dec)*sin($ha); $y = sin($dec)*cos($lat) - cos($dec)*sin($lat)*cos($ha); return calendar::compass($x,$y); } ## Azimuth ## http://kr.php.net/manual/en/function.atan2.php ## function &compass($x, $y) { if($x==0 && $y==0) return 0; // ...or return 360 $deg = ($x<0) ? rad2deg(atan2($x,$y))+360.0 : rad2deg(atan2($x,$y)); return sprintf('%.8f',$deg); // float degress } ## Azimuth ## tan(A) = -cos(dec)*sin(Ha) / (sin(dec)*cos(lat) - cos(dec)*sin(lat)*cos(Ha)) ## http://kr.php.net/manual/en/function.atan2.php ## function &polar($x, $y) { $NS = ($y>=0) ? 'N' : 'S'; $EW = ($x>=0) ? 'E' : 'W'; return $NS.$EW; } ## div by 45.0 degrees ## 337.5 - 22.5 N ## 22.5 - 67.5 NE ## 67.5 - 112.5 E ## 112.5 - 157.5 SE ## 157.5 - 202.5 S ## 202.5 - 247.5 SW ## 247.5 - 292.5 W ## 292.5 - 337.5 NW ## function &az2polar($az) { static $_polars = array('N','NE','E','SE','S','SW','W','NW','N'); $az = ($az<0) ? fmod($az,360)+360.0 : fmod($az,360); // to valid $k = floor(($az+22.5)/45); // shift and 8 pos return $_polars[$k]; } function &location_kr($l=0) { static $_locations = array ( array(126.97,37.55, '¼­¿ï'), // ¼­¿ï array(131.87,37.24, 'µ¶µµ'), // µ¶µµ array(129.37,36.04, 'Æ÷Ç×'), // Æ÷Ç× array(126.35,36.52, '¾È¸éµµ(Ãæ³²)') // ¾È¸é ); if($l === NULL) return $_locations; if(is_array($l)) { $r[0] = calendar::dms2deg($l[0],4); $r[1] = calendar::dms2deg($l[1],4); } else if(preg_match('/^[\d]+$/',$l)) $r = $_locations[$l]; else if(preg_match('/[^\d.+-]/',$l)) $r = calendar::str2deg($l); else $r = $_locations[0]; return ($r ? $r : $_locations[0]); } /*** ## JD to Local/Greenwich Sidreal Time ## http://www.jgiesen.de/astro/astroJS/sunriseJS/index.htm // in rsTL.js ## JD 2400000.5 == 1858-11-17 00:00:00 UT ## ## note: JD or TT ## function &_jd2lst($JD, $longit=0) { $MJD = $JD - 2400000.5; $MJD0 = floor($MJD); $ut = ($MJD - $MJD0) * 24.0; $t = ($MJD0 - 51544.5) / 36525.0; ## is a ut (24 hours unit) ## $gst = 6.697374558 + (1.00273790935*$ut) + (8640184.812866 + (0.093104-0.0000062*$t)*$t) * $t/3600.0; $lst = $gst + ($longit/15); $lst = ($lst<0) ? fmod($lst,24)+24.0 : fmod($lst,24); return sprintf('%.8f',$lst); // 24 hours unit (hour angle) } ***/ ## Calculate the mean sidereal time at the meridian of Greenwich of a given date. ## returns apparent sidereal time (decimal hours). ## Formula 11.1, 11.4 pg 83 Jean Meeus: Astronomical Algorithms ## http://www.jgiesen.de/elevaz/basics/meeus.htm ## ## stellarium-0.11.1/src/core/planetsephems/sideral_time.c ## result same as _jd2lst() but, this logic some good speed ## ## note: JD is UT base, not TT ## function &jd2lst($JD, $lon=0) { $D = $JD - 2451545.0; $t = $D / 36525.0; // J2000.0 base Julian Century $t2 = $t * $t; $t3 = $t * $t2; ## calculate mean angle ## $gst = 280.46061837 + (360.98564736629*$D) + (0.000387933*$t2) - ($t3/38710000.0); ## convert degress to hour angle ## $lst = ($gst+$lon) / 15; // to lst hour angle $lst = ($lst<0) ? fmod($lst,24)+24.0 : fmod($lst,24); return sprintf('%.8f',$lst); // 24 hours unit (hour angle) } ## http://eclipse.gsfc.nasa.gov/SEhelp/deltatpoly2004.html // deltaT ## http://eclipse.gsfc.nasa.gov/5MCSE/5MCSEcatalog.txt // compare of solar eclipses ## http://eclipse.gsfc.nasa.gov/5MCLE/5MKLEcatalog.txt // compare of lunar eclipses ## http://www.moshier.net/ deltaT from aa200c.zip: JPL ephemeris reader ## ## input $Y example: ## BC 0002-01-01 ==> -0001-01-01 == (int)-1 + (int)(1/12) == -0.9167 year ## ## difference of dT (cal - NASA eclipses Ephemerides) at 5MKLEcatalog.txt (VSOP87/ELP2000-82) ## - cal date: -2127 ~ 3000 ## - max = 343.43 ## - std = 79.077349064742 ## function &deltaT($Y='', &$JD=NULL) { ## check year, JD (is not TT) ## if($JD !== NULL) list($Y,$M) = calendar::_todate($JD,0); else if($Y !== '') { if(preg_match('/[^\d.+-]/',$Y)) // Y is float or integer { if(preg_match('/BC/i',$Y)) $BC = TRUE; $Y = preg_replace('/[^\d.+-]+/','',$Y); // rewrite if($BC) $Y = (abs($Y)-1) * -1; } $x = $Y - floor($Y); if($x > 0.0) { $Y = floor($Y); $M = (int)($x*12); } // not (int), see above comment else $M = 1; } else list($Y,$M) = explode(' ',date('Y n')); // else Y==NULL or empty $y = $Y + ($M-0.5)/12; if($Y > 2150) // 2151+ { $u = ($Y-1820)/100; // $Y is 'year', not $y $u2 = $u*$u; $dT = -20 + (32*$u2); $dT += 3.5 + 117.5*sin(($y-2150)/850); // patch san2@2012.01.16, valid of (Y<3000) } else if($Y > 2050) // 2051 - 2150 { $u = ($y-1820)/100; $u2 = $u*$u; $dT = -20 + (32*$u2) - (0.5628*(2150-$y)); $dT += 1.0 + 2.5*($y-2050)/100; // patch san2@2012.01.16 } else if($Y > 2005) // 2006 - 2050, 2010=66.9s, 2050=93s { $t = $y-2000; $t2 = $t*$t; $dT = 62.92 + (0.32217*$t) + (0.005589*$t2); } else if($Y > 1986) // 1987 - 2005 { $t = $y-2000; $t2 = $t*$t; $t3 = $t*$t2; $dT = 63.86 + (0.3345*$t) - (0.060374*$t2) + (0.0017275*$t3) + (0.000651814*$t2*$t2) + (0.00002373599*$t2*$t3); } else if($Y > 1961) // 1962 - 1986 { $t = $y-1975; $t2 = $t*$t; $t3 = $t*$t2; $dT = 45.45 + (1.067*$t) - ($t2/260) - ($t3/718); } else if($Y > 1940) // 1942 - 1961 { $t = $y-1950; $t2 = $t*$t; $t3 = $t*$t2; $dT = 29.07 + (0.407*$t) - ($t2/233) + ($t3/2547); } else if($Y > 1920) // 1921 -1941 { $t = $y-1920; $t2 = $t*$t; $t3 = $t*$t2; $dT = 21.20 + (0.84493*$t) - (0.076100*$t2) + (0.0020936*$t3); } else if($Y > 1900) // 1901 - 1920 { $t = $y-1900; $t2 = $t*$t; $t3 = $t*$t2; $dT = -2.79 + (1.494119*$t) - (0.0598939*$t2) + (0.0061966*$t3) - (0.000197*$t2*$t2); } else if($Y > 1860) // 1861 - 1900 { $t = $y-1860; $t2 = $t*$t; $t3 = $t*$t2; $dT = 7.62 + (0.5737*$t) - (0.251754*$t2) + (0.01680668*$t3) - (0.0004473624*$t2*$t2) + ($t2*$t3/ 233174); } else if($Y > 1800) // 1801 - 1860 { $t = $y-1800; $t2 = $t*$t; $t3 = $t*$t2; $t4 = $t*$t3; $dT = 13.72 - (0.332447*$t) + (0.0068612*$t2) + (0.0041116*$t3) - (0.00037436*$t4) + (0.0000121272*$t2*$t3) - (0.0000001699*$t3*$t3) + (0.000000000875*$t3*$t4); } else if($Y > 1700) // 1701 - 1800 { $t = $y-1700; $t2 = $t*$t; $t3 = $t*$t2; $dT = 8.83 + (0.1603*$t) - (0.0059285*$t2) + (0.00013336*$t3) - ($t2*$t2/1174000); } else if($Y > 1600) // 1601 - 1700 { $t = $y-1600; $t2 = $t*$t; $t3 = $t*$t2; $dT = 120 - (0.9808*$t) - (0.01532*$t2) + ($t3/7129); } else if($Y > 500) // 501 - 1600 { $u = ($y-1000)/100; $u2 = $u*$u; $u3 = $u*$u2; $dT = 1574.2 - (556.01*$u) + (71.23472*$u*$u) + (0.319781*$u3) - (0.8503463*$u2*$u2) - (0.005050998*$u2*$u3) + (0.0083572073*$u3*$u3); $dT += ($y>1200) ? (7*($y-1600)/400) : (-7 + 130*($y-1200)/700);// patch san2@2012.01.16 } else if($Y > -500) // -499 - 500, max dT = 17203.7 (not 17190) { $u = $y/100; $u2 = $u*$u; $u3 = $u*$u2; $dT = 10583.6 - (1014.41*$u) + (33.78311*$u2) - (5.952053*$u3) - (0.1798452*$u2*$u2) + (0.022174192*$u2*$u3) + (0.0090316521*$u3*$u3); $dT += ($y>0) ? (-151 + 133*($y-500)/500) : (-260 + 450*$y/500); // patch san2@2012.01.16 } else // -500 { $u = ($Y-1820)/100; $u2 = $u*$u; $dT = -20 + 32 * $u2; $dT += -700 + 3300*($y+500)/2500; // patch san2@2012.01.16, valid (Y<-3000) } ## Secular Acceleration of the Moon ## http://eclipse.gsfc.nasa.gov/SEcat5/secular.html ## ## c = -0.91072 * ( -25.858 + 26.0 ) * t^2 ## where: t = (year-1955)/100 ## or ## c = -0.000012932 * (y - 1955)^2 ## $t = $y - 1955; $dT += -0.000012932 * $t*$t; return sprintf('%.2f',$dT); // seconds } ## public ## function &calendar($year, $month) { list($week,$term) = calendar::month_info($year,$month); $eidx = 3; $refs = range(1,$term); // reference of days $fsat = 7 - $week; // first Saturday ## make index array such as (Sun,Sat) ## for($i=0; $i<=3; $i++) { $isat = $fsat + ($i*7); // index of Saturday $idxs[] = array($isat-6,$isat); } ## check last Saturday and Sunday ## if(($fsat+28) <= $term) $idxs[++$eidx] = array($fsat+22,$fsat+28); if(($term-$idxs[$eidx][1]) > 0) { $idxs[] = array($idxs[$eidx][0]+7,$idxs[$eidx][1]+7); $eidx++; } ## rewrite days ## for($i=0; $i<=$eidx; $i++) { for($j=$idxs[$i][0]; $j<=$idxs[$i][1]; $j++) $r[$i][] = &$refs[$j-1]; } return $r; // array } } // end of class return; // do not any print at below this line /**** example ********* $_y = 2040; $_m = 12; $r = calendar::calendar($_y,$_m); echo '
';
echo "      $_m $_y\n";
echo "Su Mo Tu We Th Fr Sa\n";

$size = sizeof($r);
for($i=0; $i<$size; $i++)
{
  printf("%2s",$r[$i][0]);
  for($j=1; $j<7; $j++) printf("%3s",$r[$i][$j]);
  echo "\n";
}
print_r($r);
**********************/

?>