PHPで日出没・月出没・月齢・潮を計算

(1/1)
PHPで二十四節気一覧を作成」「PHPで月齢を計算」では、太陽や月の位置を計算する方法を紹介した。今回は、これらを利用し、日の出・日の入り・月の出・月の入りの時刻、月齢、潮の大小を計算するPHPプログラムをつくってみる。

(2023年1月14日)計算精度を向上した。数値入力にSpinner、pahooInputDataを導入した。

目次

サンプル・プログラムの実行例

PHPで日出没・月出没・月齢を計算

サンプル・プログラム

各種暦計算、太陽や月の位置計算は、クラス pahooCalendar として分離している。
圧縮ファイルの内容
myCalendar.phpサンプル・プログラム本体。
pahooCalendar.php暦・潮位計算クラス pahooCalendar。
暦・潮位計算クラスの使い方は「PHPで二十四節気・七十二候一覧を作成」「PHPで月齢を計算」「PHPで日出没・月出没・月齢・潮を計算」「PHPで潮位を計算する」などを参照。include_path が通ったディレクトリに配置すること。
pahooInputData.phpデータ入力に関わる関数群。
使い方は「数値入力とバリデーション」「文字入力とバリデーション」などを参照。include_path が通ったディレクトリに配置すること。
myCalendar.php 更新履歴
バージョン 更新日 内容
1.5.0 2023/01/14 数値入力にSpinner、pahooInputData導入
1.4.0 2023/01/09 計算精度向上
1.3 2021/05/08 PHP8対応,リファラ・チェック改良
1.2 2020/01/02 リファラチェック追加
1.11 2018/01/03 月齢は日本時21時に変更
pahooCalendar.php 更新履歴
バージョン 更新日 内容
4.5.0 2024/03/17 ヒジュラ暦メソッドを追加
4.4.1 2024/03/17 getCabinetOfficeHolidayTable() -- bug-fix
4.4.0 2024/02/25 内閣府の祝日表を参照できるようにした
4.3.2 2023/02/11 getSolarTerm72() 表記改訂:水澤腹堅→水沢腹堅
4.3.1 2023/02/03 表記改訂:バクムーン→バックムーン,スタージャンムーン→スタージョンムーン,七十二候
pahooInputData.php 更新履歴
バージョン 更新日 内容
1.5.0 2024/01/28 exitIfExceedVersion() 追加
1.4.2 2024/01/28 exitIfLessVersion() メッセージ修正
1.4.1 2023/09/30 コメントの訂正
1.4.0 2023/09/09 $_GET, $_POST参照をfilter_input()関数に置換
1.3.0 2023/07/11 roundFloat() 追加

解説:日出・日没時刻の計算

 766: /**
 767:  * 指定した年月日の日出/日没/南中の時刻を求める(日時はローカル時間).
 768:  * 参考サイト https://www.pahoo.org/e-soul/webtech/php02/php02-44-01.shtm
 769:  * @param   int $mode 0=出, 1=没, 2=南中
 770:  * @param   int $year, $month, $day 年月日
 771:  * @param   float $longitude 観測値の経度(東経は正数)
 772:  * @param   float $latitude  観測値の緯度
 773:  * @param   float $height    観測値の高さ
 774:  * @param   float $tdiff     UTCとの時差;NULLの時はTDIFF(省略時NULL)
 775:  * @return  float 時(分秒以下は小数)
 776: */
 777: function sun_time($mode, $longitude, $latitude, $height, $year, $month, $day, $tdiff=NULL) {
 778:     //地球自転遅れ補正値(日)計算
 779:     $rotate_rev = (57.0 + 0.8 * ($year - 1990)) / 86400.0;
 780: 
 781:     //2000年1月1日力学時正午からの経過日数(日)計算
 782:     $day_progress = $this->J2000($year, $month, $day, 0, 0, 0, $tdiff);
 783: 
 784:     //逐次計算時刻(日)初期設定
 785:     $time_loop = 0.5;
 786: 
 787:     //補正値初期値
 788:     $rev = 1.0;
 789: 
 790:     //地平線伏角
 791:     $dip = 0.0353333 * sqrt($height);
 792: 
 793:     while (abs($rev> $this->CONVERGE) {
 794:         //経過ユリウス年(日)計算
 795:         //( 2000.0(2000年1月1日力学時正午)からの経過年数 (年) )
 796:         $jy = ($day_progress + $time_loop + $rotate_rev) / 365.25;
 797:         //太陽の黄経
 798:         $long_sun = $this->__longitude_sun($jy);
 799:         //太陽の距離
 800:         $dist_sun = $this->__distance_sun($jy);
 801:         //黄道 → 赤道変換
 802:         list($alpha, $delta) = $this->__eclip2equat($long_sun, 0, $jy);
 803:         //太陽の視半径
 804:         $r_sun = 0.266994 / $dist_sun;
 805:         //太陽の視差
 806:         $dif_sun = 0.0024428 / $dist_sun;
 807:         //太陽の出入高度
 808:         $height_sun = -1.0 * $r_sun - $this->ASTRO_REFRACT - $dip + $dif_sun;
 809:         //恒星時
 810:         $sidereal = $this->__sidereal($jy, $time_loop, $longitude);
 811:         //時角差計算
 812:         $hour_ang_dif = $this->hour_ang_dif($mode, $alpha, $delta, $latitude, $height_sun, $sidereal);
 813: 
 814:         //仮定時刻に対する補正値
 815:         $rev = $hour_ang_dif / 360.0;
 816:         $time_loop +$rev;
 817:     }
 818: 
 819:     return $time_loop;
 820: }

日の出、日の入りの時刻はユーザー関数 sun_time で計算する。
計算の基準となる日時は、2000年(平成12年)1月1日力学時正午からの経過年数 $jy とする。
まず、太陽の位置(視黄経、視黄緯)を計算する。黄経、黄緯(黄道座標系)については、「解説:視黄経の算出 - PHPで二十四節気・七十二候一覧を作成」で説明したとおりだ。

後述する月出・月没・月南中時刻の計算とともに、計算式は『日の出・日の入りの計算』(長沢工=著)を参考にした。
赤道座標系
次に、黄道座標系を赤道座標系(赤経・赤緯)に変換する。赤道座標系は、地球の経度・緯度を空に延長した直交座標系で、経度が赤経に、緯度が赤緯に相当する。

 605: /**
 606:  * 黄道座標から赤道座標を求める(J2000.0分点).
 607:  * 参考サイト https://www.pahoo.org/e-soul/webtech/php02/php02-44-01.shtm
 608:  * @param   float $ramda, $beta 黄経,黄緯
 609:  * @param   float $jy J2000.0からの経過年数
 610:  * @return  float (赤経,赤緯)
 611: */
 612: function __eclip2equat($rambda, $beta, $jy) {
 613:     $e  = (float)deg2rad(23.439291 - 0.000130042 * $jy);        //黄道傾角
 614:     $rambda = (float)deg2rad($rambda);
 615:     $beta   = (float)deg2rad($beta);
 616: 
 617:     $a  =      (float)cos($beta* cos($rambda);
 618:     $b  = (float)-1.0 * sin($beta* sin($e);
 619:     $b +=      (float)cos($beta* sin($rambda* cos($e);
 620:     $c  =      (float)sin($beta* cos($e);
 621:     $c +=      (float)cos($beta* sin($rambda* sin($e);
 622: 
 623:     $alpha  = (float)$b / $a;
 624:     $alpha  = (float)rad2deg(atan($alpha));
 625:     if ($a < 0.0)        (float)$alpha +180.0;
 626:     if ($alpha < 0.0)    (float)$alpha +360.0;
 627: 
 628:     $delta   = (float)rad2deg(asin($c));
 629: 
 630:     return array($alpha, $delta);
 631: }

 633: /**
 634:  * 黄道座標から赤道座標を求める(指定したローカル時間分点).
 635:  * 参考サイト https://www.pahoo.org/e-soul/webtech/php02/php02-44-01.shtm
 636:  * @param   float $ramda, $beta 黄経,黄緯
 637:  * @param   float $hour, $min, $sec 時分秒(ローカル時間)
 638:  * @param   float $tdiff UTCとの時差;NULLの時はTDIFF(省略時NULL)
 639:  * @return  float (赤経,赤緯)
 640: */
 641: function eclip2equat($rambda, $beta, $year, $month, $day, $hour, $min, $sec, $tdiff=NULL) {
 642:     $jy = $this->Gregorian2JY($year, $month, $day, $hour, $min, $sec, $tdiff);
 643: 
 644:     return $this->__eclip2equat($rambda, $beta, $jy);
 645: }

解説:月出・月没・月南中時刻の計算

1736: /**
1737:  * 指定した年月日における月の出/月の入り/南中の時刻を求める.
1738:  * 参考サイト https://www.pahoo.org/e-soul/webtech/php02/php02-44-01.shtm
1739:  * @param   int $mode 0=出, 1=没, 2=南中
1740:  * @param   int $year, $month, $day  グレゴリオ暦による年月日
1741:  * @param   float $longitude 観測値の経度(東経は正数)
1742:  * @param   float $latitude  観測値の緯度
1743:  * @param   float $height    観測値の高さ
1744:  * @param   float $tdiff     UTCとの時差;NULLの時はTDIFF(省略時NULL)
1745:  * @return  float 時刻(単位:日)/FALSE 月出/月没がない
1746: */
1747: function moon_time($mode, $longitude, $latitude, $height, $year, $month, $day) {
1748:     //地球自転遅れ補正値(日)計算
1749:     $rotate_rev = (57.0 + 0.8 * ($year - 1990.0)) / 86400.0;
1750: 
1751:     //2000年1月1日力学時正午からの経過日数(日)計算
1752:     $day_progress = $this->J2000($year, $month, $day, 0, 0, 0);
1753: 
1754:     //逐次計算時刻(日)初期設定
1755:     $time_loop = 0.5;
1756: 
1757:     //補正値初期値
1758:     $rev = 1.0;
1759: 
1760:     //地平線伏角
1761:     $dip = 0.0353333 * sqrt($height);
1762: 
1763:     $diff_moon = 0.0;
1764:     $height_moon = 0.0;
1765:     while (abs($rev> $this->CONVERGE) {
1766:         //経過ユリウス年(日)計算
1767:         //( 2000.0(2000年1月1日力学時正午)からの経過年数 (年) )
1768:         $jy = ($day_progress + $time_loop + $rotate_rev) / 365.25;
1769:         //月の黄経
1770:         $long_moon = $this->__longitude_moon($jy);
1771:         //月の黄緯
1772:         $lat_moon = $this->__latitude_moon($jy);
1773:         //黄道 → 赤道変換
1774:         list($alpha, $delta) = $this->__eclip2equat($long_moon, $lat_moon, $jy);
1775:         if ($mode !2) {
1776:             //月の視差
1777:             $dif_moon = $this->__dif_moon($jy);
1778:             //月の出没高度
1779:             $height_moon = -1.0 * $this->ASTRO_REFRACT - $dip + $dif_moon;
1780:         }
1781:         //恒星時
1782:         $sidereal = $this->__sidereal($jy, $time_loop, $longitude);
1783:         //時角差計算
1784:         $hour_ang_dif = $this->hour_ang_dif($mode, $alpha, $delta, $latitude, $height_moon, $sidereal);
1785: 
1786:         //仮定時刻に対する補正値
1787:         $rev = $hour_ang_dif / 347.8;
1788:         $time_loop +$rev;
1789:     }
1790: 
1791:     //月出/月没がない場合は FALSE とする
1792:     return ($time_loop < 0.0 || $time_loop >1.0? FALSE : $time_loop;
1793: }

月の出、月の入り、月の南中(真南に来ること)の時刻はユーザー関数 moon_time で計算する。方法は太陽の場合と同じである。
ここまでで計算した座標は、月の中心の位置をあらわす。月の出、月の入りについては、月の中心座標が地平線を通過したときと定義されているので、これをそのまま時刻計算に持ち込めばよい。ただし、視差を考慮する必要がある。
なお、日の出は太陽の上縁が地平線に接した時刻、日の入りは太陽の下縁が地平線に接した時刻と定義されている。

解説:潮の計算

1915: /**
1916:  * 指定した日時の潮を求める(日時はローカル時間).
1917:  * 参考サイト https://www.pahoo.org/e-soul/webtech/php02/php02-44-01.shtm#php_tide
1918:  * @param   int $year, $month, $day  グレゴリオ暦による年月日
1919:  * @param   float $tdiff     UTCとの時差;NULLの時はTDIFF(省略時NULL)
1920:  * @return  string 潮
1921: */
1922: function tide($year, $month, $day, $hour, $min, $sec, $tdiff=NULL) {
1923:     //黄経差=>潮(気象庁方式)
1924:     static $table = array(
1925:  36 => '大潮',
1926:  72 => '中潮',
1927: 108 => '小潮',
1928: 120 => '長潮',
1929: 132 => '若潮',
1930: 168 => '中潮',
1931: 216 => '大潮',
1932: 252 => '中潮',
1933: 288 => '小潮',
1934: 300 => '長潮',
1935: 312 => '若潮',
1936: 348 => '中潮',
1937: 360 => '大潮'
1938: );
1939: 
1940:     $longitude_sun  = $this->longitude_sun($year, $month, $day, $hour, $min, $sec, $tdiff);
1941:     $longitude_moon = $this->longitude_moon($year, $month, $day, $hour, $min, $sec, $tdiff);
1942:     //Δλ=λmoon-λsun
1943:     $delta_rm = $this->__angle($longitude_moon - $longitude_sun);
1944: 
1945:     foreach ($table as $key=>$val) {
1946:         if ($delta_rm < $key) {
1947:             $tide = $val;
1948:             break;
1949:         }
1950:     }
1951: 
1952:     return $tide;
1953: }

月と太陽の位置関係によって潮汐が起きる。

潮の大小は、月と太陽の位相(黄経差)でほぼ決まる。
ユーザー関数 longitude_sunlongitude_moon の差をとって、潮の大小を取得する関数が tide である。
黄経差は気象庁方式を採った。つまり、下記のようになる。
黄経差 潮の大小
348~36度 大潮
36~72度 中潮
72~108度 小潮
108~120度 長潮
120~132度 若潮
132~168度 中潮
168~216度 小潮
216~252度 中潮
252~288度 小潮
288~300度 長潮
300~316度 若潮
312~348度 中潮

質疑応答

【質問】 ニックリネーム様
はじめまして。
・月齢・月出・月没・月南中
をAndroidスマホのウィジェットで表示するアプリを作成中で、ぱふぅ家様のページにあるPHPソースコードを流用して実装したいと思っています(Javaに変換)。
広告付きアプリにはウンザリしており、無料・広告無しで公開しアプリの説明で参考情報としてぱふぅ家様の該当ページへのリンクを記載いたします。
二次利用に関する説明ページは確認済みですが、もし何か問題がございましたらご指摘いただけますでしょうか。
【回答】
リンクを記載していただけるとのこと、ありがとうございます。
どうぞご活用ください。
【質問】 ニックリネーム様
ありがとうございます。Javaで実装はほぼ終わったのですが
var $TDIFF = 9.0;
を例えば $TDIFF=8.0; にしても月出/月没の時間が1時間ではなく数分しかずれません。
TDIFF=9なら月出/月没/南中の出力結果はぱふぅ様のページと同じになるのでコードの移植はできていると思うのですがPHP環境で試せていません。誠に勝手なお願いで恐縮ですがPHP環境でも同様か、ご確認いただけませんでしょうか。
【回答】
$TDIFF は、日本標準時をベースに用意された近似式に対応するための補正値です。他国の標準時に変換することはできません。9.0固定にしてください。

参考書籍

表紙 日の出・日の入りの計算
著者 長沢工
出版社 地人書館
サイズ 単行本
発売日 1999年12月
価格 1,650円(税込)
ISBN 9784805206348
 

参考サイト

(この項おわり)
header