目次
サンプル・プログラムの実行例
サンプル・プログラム
supermoon.php | サンプル・プログラム本体。 |
pahooCalendar.php | 暦・潮位計算クラス pahooCalendar。 暦・潮位計算クラスの使い方は「PHPで二十四節気・七十二候一覧を作成」「PHPで月齢を計算」「PHPで日出没・月出没・月齢・潮を計算」「PHPで潮位を計算する」などを参照。include_path が通ったディレクトリに配置すること。 |
pahooInputData.php | データ入力に関わる関数群。 使い方は「数値入力とバリデーション」「文字入力とバリデーション」などを参照。include_path が通ったディレクトリに配置すること。 |
バージョン | 更新日 | 内容 |
---|---|---|
1.5.0 | 2023/01/14 | 数値入力にSpinner、pahooInputData導入 |
1.4.0 | 2023/01/09 | pahooCalendarクラスの計算精度を向上 |
1.3.0 | 2021/01/04 | 満月の日を取得するアルゴリズムを見直した |
1.2 | 2021/01/04 | PHP8対応,満月の呼び名等を追加 |
1.1 | 2018/01/03 | 明るさの比などを一覧表示 |
バージョン | 更新日 | 内容 |
---|---|---|
4.3.2 | 2023/02/11 | getSolarTerm72() 表記改訂:水澤腹堅→水沢腹堅 |
4.3.1 | 2023/02/03 | 表記改訂:バクムーン→バックムーン,スタージャンムーン→スタージョンムーン,七十二候 |
4.3.0 | 2023/01/14 | コメント表記などを見直した,tenshanichi()追加 |
4.2.0 | 2023/01/11 | getTimeDifference(),setTimeDifference()追加 |
4.1.0 | 2023/01/09 | 太陽,月の位置計算の基準をUTCに変更した |
バージョン | 更新日 | 内容 |
---|---|---|
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() 追加 |
準備:初期値など
36: //指定できる西暦年の範囲
37: define('MIN_YEAR', 1901);
38: define('MAX_YEAR', 2099);
39:
40: //表示言語(jp:日本語, en:英語, en3:英語略記)
41: define('LANGUAGE', 'jp');
42:
43: //世界時からの時差(日本標準時)
44: define('UTCDIFF', +9.0);
45:
46: //計算期間(月)
47: define('CALC_TERM', 12);
48:
49: //視半径が最小/最大の時の背景色
50: define('MIN_COLOR', '88EEFF');
51: define('MAX_COLOR', 'FFEE88');
52:
53: //Spinner - jQuery UI を使用するかどうか
54: define('USESPINNER', TRUE);
55:
56: //数値増減クリックで即判定するかどうか(TRUE:即判定,FALE:判定ボタンを用意)
57: define('ONCHANGE', FALSE);
58:
59: //表示幅(単位:ピクセル)
60: define('WIDTH', 600);
61:
62: //require_once()で呼ぶファイルはinclude_pathが通っているフォルダに配置すること。
63: //暦計算クラス
64: require_once('pahooCalendar.php');
65:
66: //データ入力に関わる関数群
67: require_once('pahooInputData.php');
月齢、月の視半径、各種カレンダー計算は、ユーザークラス "pahooCalendar" に用意したメソッド群を利用する。
オブジェクト生成時に、表示言語として "ja"(日本語)を、世界時との時差としてユーザー定義の定数 UTCDIFF を渡しておく。こうすることで、pahooCalendar クラスが出力する文字列は日本語に、日時計算は時差 UTCDIFF がある前提で計算を行う。
数値入力に jQuery UI の Spinner を使用している。設定でOFFにすることもできる。Spinner の使い方については、「Spinner - jQuery UI - PHPで素数かどうか判定」をご覧いただきたい。
入力した数値の取得とバリデーションチェックに、ユーザー定義クラス群 "pahooInputData.php" を利用している。
準備:次の満月の日時を求める
一方、月齢は朔の日(新月の日)を第1日とする日数であるから、月齢15が必ずしも満月の日になるとは限らない。
1807: /**
1808: * 指定した日時の次の満月の日時を求める(日時はローカル時間).
1809: * 太陽と月の黄緯差180度になる日時を近似計算で求める.
1810: * 参考サイト https://www.pahoo.org/e-soul/webtech/php02/php02-50-01.shtm
1811: * @param int $year, $month, $day 年月日(グレゴリオ暦)
1812: * @param float $hour, $min, $sec 時分秒(ローカル時間)
1813: * @param float $tdiff UTCとの時差;NULLの時はTDIFF参照
1814: * @return array($year, $month, $day, $hour, $min, $sec) 日時(ローカル時間)
1815: */
1816: function next_fullmoon($year, $month, $day, $hour, $min, $sec, $tdiff=NULL) {
1817: $dif = 29.55; //一朔望月(近似計算の指標)
1818: $jd = $this->Gregorian2JD($year, $month, $day, $hour, $min, $sec, $tdiff);
1819: $jdc = (float)$jd;
1820:
1821: //ニュートン法による近似計算
1822: for ($i = 1; $i < 25; $i++) {
1823: list($year, $month, $day, $hour, $min, $sec) = $this->JD2Gregorian($jdc, $tdiff);
1824: $ym = $this->longitude_moon($year, $month, $day, $hour, $min, $sec, $tdiff, $tdiff);
1825: $ys = $this->longitude_sun($year, $month, $day, $hour, $min, $sec, $tdiff, $tdiff);
1826:
1827: //太陽と月の黄緯差180度を目指す.
1828: $dy = $ym - $ys - 180.0;
1829:
1830: //引き込み範囲に入ったら補正する.
1831: if ($dy <= -360.0) {
1832: $dy += 360.0;
1833: } else if ($dy >= 0.0) {
1834: $dy -= 360.0;
1835: }
1836:
1837: //誤差内に入ったらループを脱出する.
1838: if ($dy >= 0.0 && $dy <= 0.0001) break;
1839: if ($dy < -0.0 && $dy >= -0.0001) break;
1840:
1841: $dd = $dy / $dif;
1842: $jdc -= $dd;
1843: }
1844:
1845: return array($year, $month, $day, $hour, $min, $sec);
1846: }
太陽の視黄経の計算メソッド longitude_sun と月の視黄経の計算メソッド longitude_moon はすでに説明したとおりだが、黄経値から年月日を計算する逆関数は存在しないため、近似計算によって求めている。このため、国立天文台が発表する時刻と数分のズレがある。
解説:月の視半径を求める
1620: /**
1621: * J2000.0からの経過年数における月の視差(度)を求める。
1622: * 参考サイト https://www.pahoo.org/e-soul/webtech/php02/php02-44-01.shtm
1623: * @param float $jy 2000.0からの経過年数
1624: * @return float 月の視差(度)
1625: */
1626: function __dif_moon($jy) {
1627: $p_moon = 0.0003 * sin(deg2rad($this->__angle(227.0 + 4412.0 * $jy)));
1628: $p_moon += 0.0004 * sin(deg2rad($this->__angle(194.0 + 3773.4 * $jy)));
1629: $p_moon += 0.0005 * sin(deg2rad($this->__angle(329.0 + 8545.4 * $jy)));
1630: $p_moon += 0.0009 * sin(deg2rad($this->__angle(100.0 + 13677.3 * $jy)));
1631: $p_moon += 0.0028 * sin(deg2rad($this->__angle( 0.0 + 9543.98 * $jy)));
1632: $p_moon += 0.0078 * sin(deg2rad($this->__angle(325.7 + 8905.34 * $jy)));
1633: $p_moon += 0.0095 * sin(deg2rad($this->__angle(190.7 + 4133.35 * $jy)));
1634: $p_moon += 0.0518 * sin(deg2rad($this->__angle(224.98 + 4771.989 * $jy)));
1635: $p_moon += 0.9507 * sin(deg2rad($this->__angle(90.0)));
1636:
1637: return $p_moon;
1638: }
1640: /**
1641: * 指定した日時における月の視差(度)を求める(日時はローカル時間)。
1642: * 参考サイト https://www.pahoo.org/e-soul/webtech/php02/php02-44-01.shtm
1643: * @param int $year, $month, $day グレゴリオ暦による年月日
1644: * @param float $hour, $min, $sec 時分秒(ローカル時間)
1645: * @param float $tdiff UTCとの時差;NULLの時はTDIFF
1646: * @return float 月の視差
1647: */
1648: function dif_moon($year, $month, $day, $hour, $min, $sec, $tdiff=NULL) {
1649: $jy = $this->Gregorian2JY($year, $month, $day, $hour, $min, $sec, $tdiff);
1650:
1651: return $this->__dif_moon($jy);
1652: }
1654: /**
1655: * 指定した日時における月の視半径(度)を求める(日時はローカル時間)。
1656: * 参考サイト https://www.pahoo.org/e-soul/webtech/php02/php02-50-01.shtm
1657: * @param int $year, $month, $day グレゴリオ暦による年月日
1658: * @param float $hour, $min, $sec 時分秒(ローカル時間)
1659: * @param float $tdiff UTCとの時差;NULLの時はTDIFF
1660: * @return float 月の視半径(度)
1661: */
1662: function rad_moon($year, $month, $day, $hour, $min, $sec, $tdiff=NULL) {
1663: $dif = $this->dif_moon($year, $month, $day, $hour, $min, $sec, $tdiff);
1664: $rad = asin(0.2725 * sin(deg2rad($dif)));
1665:
1666: return rad2deg($rad);
1667: }
解説:ある期間に起きる満月と視半径を計算
201: /**
202: * ある期間に起きる満月と視半径を計算
203: * @param int $year 開始年(西暦)
204: * @param int $month 開始月
205: * @param int $term 計算期間(月)
206: * @param array $items 計算結果を格納する配列
207: * @return int 満月の回数
208: */
209: function calcSuperMoon($year, $month, $term, &$items) {
210: //暦計算に関わるクラス
211: $pcl = new pahooCalendar(LANGUAGE, UTCDIFF);
212:
213: $i = $cnt = 0;
214: $day = 1;
215: while ($i < $term) {
216: //次の満月の日時を求める
217: list($year1, $month1, $day1, $hour1, $min1, $sec1) =$pcl->next_fullmoon($year, $month, $day, 0, 0, 0);
218: $items[$cnt]['year'] = $year1;
219: $items[$cnt]['month'] = $month1;
220: $items[$cnt]['day'] = $day1;
221: $items[$cnt]['week'] = $pcl->getWeekString($year1, $month1, $day1);
222: $items[$cnt]['hour'] = $hour1;
223: $items[$cnt]['min'] = $min1 + round($sec1 / 60.0, 0);
224: //月の視半径
225: $items[$cnt]['rad'] = $pcl->rad_moon($year1, $month1, $day1, $hour1, $min1, $sec1);
226: //満月の呼び名
227: $items[$cnt]['name'] = $pcl->getFullMoonNickname($month1);
228: //次のパラメータを用意する
229: $cnt++;
230: $year = $year1;
231: if ($month < $month1) $i++;
232: $month = $month1;
233: $day = $day1 + 20.0; //次の計算基準は26日後
234: if ($day > $pcl->getDaysInMonth($year, $month)) {
235: $day = 1;
236: $month++;
237: $i++;
238: if ($month > 12) {
239: $month = 1;
240: $year++;
241: }
242: }
243: }
244: //オブジェクト解放
245: $pcl = NULL;
246:
247: return $cnt;
248: }
解説:満月の呼び名
1888: /**
1889: * 指定した月の満月の呼び名を求める.
1890: * 参考サイト https://www.pahoo.org/e-soul/webtech/php02/php02-50-01.shtm
1891: * @param int $month 月
1892: * @return string 満月の呼び名
1893: */
1894: function getFullMoonNickname($month) {
1895: $table_jp = array(
1896: 'ウルフムーン',
1897: 'スノームーン',
1898: 'ワームムーン',
1899: 'ピンクムーン',
1900: 'フラワームーン',
1901: 'ストロベリームーン',
1902: 'バックムーン', //または「バクムーン」.発音はbʌkだが,buckskinをバックスキンと読むことから,ここでは「バクムーン」にした.
1903: 'スタージョンムーン', //または「スタージャンムーン」.Twitterでアンケートをとて「スタージョンムーン」にした. https://twitter.com/papa_pahoo/status/1620259072871395328
1904: 'ハーベストムーン',
1905: 'ハンターズムーン',
1906: 'ビーバームーン',
1907: 'コールドムーン'
1908: );
1909:
1910: $table_en = array(
1911: 'Wolf Moon',
1912: 'Snow Moon',
1913: 'Worm Moon',
1914: 'Pink Moon',
1915: 'Flower Moon',
1916: 'Strawberry Moon',
1917: 'Buck Moon',
1918: 'Sturgeon Moon',
1919: 'Harvest Moon',
1920: 'Hunter\#x27;s Moon',
1921: 'Beaver Moon',
1922: 'Cold Moon'
1923: );
1924:
1925: $month = (int)$month;
1926: if (($month >= 1) && ($month << 12)) {
1927: if ($this->language == 'jp') {
1928: $name = $table_jp[$month - 1];
1929: } else {
1930: $name = $table_en[$month - 1];
1931: }
1932: } else {
1933: $name = '';
1934: }
1935:
1936: return $name;
1937: }
7月の Buck Moon の buk(雄ジカ)は発音はbʌkだが、buckskinをバックスキンと読むことから、ここでは「バクムーン」にした。
8月の Sturgeon Moon の sturgeon(チョウザメ)の発音はstɚːdʒənだが、Wikipedia日本語版にある Sturgeon をもつ人名の表記は揺れている。
- ウィリアム・スタージャン - イギリスの物理学者。
- シオドア・スタージョン - アメリカのSF作家。
- ニコラ・スタージョン - スコットランドの政治家。
- ローリン・S・スタージョン - アメリカの映画監督
8月の満月「スタージャンムーン」のカタカナ表記を見直そうかどうか迷っています。
— パパぱふぅ@𝙥𝙖𝙝𝙤𝙤.𝙤𝙧𝙜 (@papa_pahoo) 2023年1月31日
英語表記 Sturgeon Moon
Sturgeonは「チョウザメ」。
よろしければアンケートにご回答ください。
解説:一覧表作成
251: /**
252: * 満月一覧から表示用HTMLを求める.
253: * @param array $items 計算結果
254: * @return string HTML文字列
255: */
256: function makeTable($items) {
257: //最大・最小の視半径を求める
258: $minrad = 999;
259: $minid = -1;
260: $maxrad = 0;
261: $maxid = -1;
262: foreach ($items as $key=>$item) {
263: if ($item['rad'] < $minrad) {
264: $minrad = $item['rad'];
265: $minid = $key;
266: }
267: if ($item['rad'] > $maxrad) {
268: $maxrad = $item['rad'];
269: $maxid = $key;
270: }
271: }
272:
273: //一覧表作成
274: $width = WIDTH;
275: $outstr =<<< EOT
276: <table style="width:{$width};">
277: <tr><th>年月日・時</th><th colspan="2">月の視半径<br /><span class="comp">(最小半径を100%)</span></th><th>明るさの比<br /><span class="comp">(最小半径を100%)</span></th><th>呼び名</th></tr>
278:
279: EOT;
280: foreach ($items as $key=>$item) {
281: $ymd = sprintf("%04d年%02d月%02d日(%s) %02d:%02d",
282: $item['year'], $item['month'], $item['day'], $item['week'], $item['hour'], $item['min']);
283: $mm = intval($item['rad'] * 60);
284: $s1 = intval(($item['rad'] * 60 - $mm) * 60);
285: $s2 = ($item['rad'] * 60 - $mm - $s1 / 60) * 60 * 100;
286: $rad = sprintf("%2d'%02d\".%02d", $mm, $s1, $s2);
287: $rat = sprintf("%3.1f", $item['rad'] / $minrad * 100);
288: $brg = sprintf("%3.1f", pow($item['rad'] / $minrad, 2) * 100);
289:
290: //背景色
291: if ($key == $minid) {
292: $color = ' style="background-color:#' . MIN_COLOR . ';"';
293: } else if ($key == $maxid) {
294: $color = ' style="background-color:#' . MAX_COLOR . ';"';
295: } else {
296: $color = '';
297: }
298:
299: $outstr .=<<< EOT
300: <tr{$color}>
301: <td>{$ymd}</td>
302: <td>{$rad}</td>
303: <td>{$rat}%</td>
304: <td>{$brg}%</td>
305: <td>{$item['name']}</td>
306: </tr>
307:
308: EOT;
309: }
310: $outstr .=<<< EOT
311: </table>
312: </body>
313:
314: EOT;
315:
316: return $outstr;
317: }
冒頭で、期間中の最小半径を求める。
これを基準に、視半径の比率、明るさの比率(半径の2乗)を計算し、一覧表にしてゆく。
活用例
参考サイト
- PHPで月齢を計算:ぱふぅ家のホームページ
- PHPで二十四節気・七十二候一覧を作成:ぱふぅ家のホームページ
- スーパームーン;AstroArts
- 「スーパームーン」ってなに?:国立天文台
- 暦Wiki/月の満ち欠け/月齢と満ち欠け]:国立天文台暦計算室
- 明日はスーパームーン:鹿角平天文台通信
- スーパームーンを調べる:みんなの知識 ちょっと便利帳
「PHPで月齢を計算」で月齢を求めるプログラムを作ったが、今回は満月の時の月の大きさ(視半径)を計算するプログラムを作ってみることにする。
(2023年2月3日)表記改訂:バクムーン→バックムーン,スタージャンムーン→スタージョンムーン
(2023年1月14日)数値入力にSpinner、pahooInputDataを導入した。
(2022年12月26日)満月の日を取得するアルゴリズムを見直した。