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

サンプル・プログラム
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.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 | 表記改訂:バクムーン→バックムーン,スタージャンムーン→スタージョンムーン,七十二候 |
バージョン | 更新日 | 内容 |
---|---|---|
1.8.0 | 2024/11/12 | validRegexPattern() 追加 |
1.7.0 | 2024/10/09 | validURL() validEmail() 追加 |
1.6.0 | 2024/10/07 | isButton() -- buttonタグに対応 |
1.5.0 | 2024/01/28 | exitIfExceedVersion() 追加 |
1.4.2 | 2024/01/28 | exitIfLessVersion() メッセージ修正 |
準備:初期値など
supermoon.php
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が必ずしも満月の日になるとは限らない。
pahooCalendar.php
1874: /**
1875: * 指定した日時の次の満月の日時を求める(日時はローカル時間).
1876: * 太陽と月の黄緯差180度になる日時を近似計算で求める.
1877: * 参考サイト https://www.pahoo.org/e-soul/webtech/php02/php02-50-01.shtm
1878: * @param int $year, $month, $day 年月日(グレゴリオ暦)
1879: * @param float $hour, $min, $sec 時分秒(ローカル時間)
1880: * @param float $tdiff UTCとの時差;NULLの時はTDIFF参照
1881: * @return array($year, $month, $day, $hour, $min, $sec) 日時(ローカル時間)
1882: */
1883: function next_fullmoon($year, $month, $day, $hour, $min, $sec, $tdiff=NULL) {
1884: $dif = 29.55; //一朔望月(近似計算の指標)
1885: $jd = $this->Gregorian2JD($year, $month, $day, $hour, $min, $sec, $tdiff);
1886: $jdc = (float)$jd;
1887:
1888: //ニュートン法による近似計算
1889: for ($i = 1; $i < 25; $i++) {
1890: list($year, $month, $day, $hour, $min, $sec) = $this->JD2Gregorian($jdc, $tdiff);
1891: $ym = $this->longitude_moon($year, $month, $day, $hour, $min, $sec, $tdiff, $tdiff);
1892: $ys = $this->longitude_sun($year, $month, $day, $hour, $min, $sec, $tdiff, $tdiff);
1893:
1894: //太陽と月の黄緯差180度を目指す.
1895: $dy = $ym - $ys - 180.0;
1896:
1897: //引き込み範囲に入ったら補正する.
1898: if ($dy <= -360.0) {
1899: $dy += 360.0;
1900: } else if ($dy >= 0.0) {
1901: $dy -= 360.0;
1902: }
1903:
1904: //誤差内に入ったらループを脱出する.
1905: if ($dy >= 0.0 && $dy <= 0.0001) break;
1906: if ($dy < -0.0 && $dy >= -0.0001) break;
1907:
1908: $dd = $dy / $dif;
1909: $jdc -= $dd;
1910: }
1911:
1912: return array($year, $month, $day, $hour, $min, $sec);
1913: }
太陽の視黄経の計算メソッド longitude_sun と月の視黄経の計算メソッド longitude_moon はすでに説明したとおりだが、黄経値から年月日を計算する逆関数は存在しないため、近似計算によって求めている。このため、国立天文台が発表する時刻と数分のズレがある。
解説:月の視半径を求める
pahooCalendar.php
1687: /**
1688: * J2000.0からの経過年数における月の視差(度)を求める。
1689: * 参考サイト https://www.pahoo.org/e-soul/webtech/php02/php02-44-01.shtm
1690: * @param float $jy 2000.0からの経過年数
1691: * @return float 月の視差(度)
1692: */
1693: function __dif_moon($jy) {
1694: $p_moon = 0.0003 * sin(deg2rad($this->__angle(227.0 + 4412.0 * $jy)));
1695: $p_moon += 0.0004 * sin(deg2rad($this->__angle(194.0 + 3773.4 * $jy)));
1696: $p_moon += 0.0005 * sin(deg2rad($this->__angle(329.0 + 8545.4 * $jy)));
1697: $p_moon += 0.0009 * sin(deg2rad($this->__angle(100.0 + 13677.3 * $jy)));
1698: $p_moon += 0.0028 * sin(deg2rad($this->__angle( 0.0 + 9543.98 * $jy)));
1699: $p_moon += 0.0078 * sin(deg2rad($this->__angle(325.7 + 8905.34 * $jy)));
1700: $p_moon += 0.0095 * sin(deg2rad($this->__angle(190.7 + 4133.35 * $jy)));
1701: $p_moon += 0.0518 * sin(deg2rad($this->__angle(224.98 + 4771.989 * $jy)));
1702: $p_moon += 0.9507 * sin(deg2rad($this->__angle(90.0)));
1703:
1704: return $p_moon;
1705: }
pahooCalendar.php
1707: /**
1708: * 指定した日時における月の視差(度)を求める(日時はローカル時間)。
1709: * 参考サイト https://www.pahoo.org/e-soul/webtech/php02/php02-44-01.shtm
1710: * @param int $year, $month, $day グレゴリオ暦による年月日
1711: * @param float $hour, $min, $sec 時分秒(ローカル時間)
1712: * @param float $tdiff UTCとの時差;NULLの時はTDIFF
1713: * @return float 月の視差
1714: */
1715: function dif_moon($year, $month, $day, $hour, $min, $sec, $tdiff=NULL) {
1716: $jy = $this->Gregorian2JY($year, $month, $day, $hour, $min, $sec, $tdiff);
1717:
1718: return $this->__dif_moon($jy);
1719: }
pahooCalendar.php
1721: /**
1722: * 指定した日時における月の視半径(度)を求める(日時はローカル時間)。
1723: * 参考サイト https://www.pahoo.org/e-soul/webtech/php02/php02-50-01.shtm
1724: * @param int $year, $month, $day グレゴリオ暦による年月日
1725: * @param float $hour, $min, $sec 時分秒(ローカル時間)
1726: * @param float $tdiff UTCとの時差;NULLの時はTDIFF
1727: * @return float 月の視半径(度)
1728: */
1729: function rad_moon($year, $month, $day, $hour, $min, $sec, $tdiff=NULL) {
1730: $dif = $this->dif_moon($year, $month, $day, $hour, $min, $sec, $tdiff);
1731: $rad = asin(0.2725 * sin(deg2rad($dif)));
1732:
1733: return rad2deg($rad);
1734: }
これを rad_moon として実装している。
\[ rad = sin^{-1}(0.2725 \times sin(dif)) \]
解説:ある期間に起きる満月と視半径を計算
supermoon.php
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: }
解説:満月の呼び名
pahooCalendar.php
1955: /**
1956: * 指定した月の満月の呼び名を求める.
1957: * 参考サイト https://www.pahoo.org/e-soul/webtech/php02/php02-50-01.shtm
1958: * @param int $month 月
1959: * @return string 満月の呼び名
1960: */
1961: function getFullMoonNickname($month) {
1962: $table_jp = array(
1963: 'ウルフムーン',
1964: 'スノームーン',
1965: 'ワームムーン',
1966: 'ピンクムーン',
1967: 'フラワームーン',
1968: 'ストロベリームーン',
1969: 'バックムーン', //または「バクムーン」.発音はbʌkだが,buckskinをバックスキンと読むことから,ここでは「バクムーン」にした.
1970: 'スタージョンムーン', //または「スタージャンムーン」.Twitterでアンケートをとて「スタージョンムーン」にした. https://twitter.com/papa_pahoo/status/1620259072871395328
1971: 'ハーベストムーン',
1972: 'ハンターズムーン',
1973: 'ビーバームーン',
1974: 'コールドムーン'
1975: );
1976:
1977: $table_en = array(
1978: 'Wolf Moon',
1979: 'Snow Moon',
1980: 'Worm Moon',
1981: 'Pink Moon',
1982: 'Flower Moon',
1983: 'Strawberry Moon',
1984: 'Buck Moon',
1985: 'Sturgeon Moon',
1986: 'Harvest Moon',
1987: 'Hunter\#x27;s Moon',
1988: 'Beaver Moon',
1989: 'Cold Moon'
1990: );
1991:
1992: $month = (int)$month;
1993: if (($month >= 1) && ($month << 12)) {
1994: if ($this->language == 'jp') {
1995: $name = $table_jp[$month - 1];
1996: } else {
1997: $name = $table_en[$month - 1];
1998: }
1999: } else {
2000: $name = '';
2001: }
2002:
2003: return $name;
2004: }

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は「チョウザメ」。
よろしければアンケートにご回答ください。
解説:一覧表作成
supermoon.php
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日)満月の日を取得するアルゴリズムを見直した。