目次
サンプル・プログラムの実行例
サンプル・プログラム
cosmicCalendar.php | サンプル・プログラム本体。 |
cosmicCalendar.xml | イベント・ファイル。 |
pahooInputData.php | データ入力に関わる関数群。 使い方は「数値入力とバリデーション」「文字入力とバリデーション」などを参照。include_path が通ったディレクトリに配置すること。 |
pahooCalendar.php | 暦計算クラス pahooCalendar。 暦計算クラスの使い方は「PHPで日出没・月出没・月齢・潮を計算」を参照。include_path が通ったディレクトリに配置すること。 |
バージョン | 更新日 | 内容 |
---|---|---|
1.6.0 | 2023/10/15 | sigcalendar()のbug-fix, pahooInputData導入 |
1.5.0 | 2022/12/30 | 1月は時分まで表示するようにした |
1.42 | 2022/07/21 | bug-fix,イベント・ファイル更新 |
1.41 | 2021/05/12 | bug-fix |
1.4 | 2021/01/16 | PHP8対応 |
バージョン | 更新日 | 内容 |
---|---|---|
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() 追加 |
バージョン | 更新日 | 内容 |
---|---|---|
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 | 表記改訂:バクムーン→バックムーン,スタージャンムーン→スタージョンムーン,七十二候 |
イベント・ファイル
同梱したファイルには、宇宙の誕生から現在までの主要イベントを記入済みである。
このイベント・ファイルを編集すれば、日本史や家族史を使った宇宙カレンダー(365日カレンダーと呼んだ方がいいかもしれない)を表示することができる。
1: <?xml version="1.0" encoding="utf-8" ?>
2: <!-- 年代記 -->
3: <cosmicCalendar>
4: <!-- キャプション -->
5: <caption>
6: <label>宇宙カレンダー</label>
7: <description>宇宙誕生から現在までを1年に圧縮</description>
8: </caption>
9: <!-- 開始 -->
10: <start>
11: <label>宇宙誕生</label>
12: <before unit="year">138E+8</before>
13: <description></description>
14: </start>
15: <finish>
16: <label>現在</label>
17: <before unit="year">0</before>
18: <description></description>
19: </finish>
20:
21: <!-- 以下、イベント・データベース -->
22: <event>
23: <label>宇宙の晴れ上がり</label>
24: <!-- 開始イベントからの年数を記載するときは after -->
25: <after unit="year">30E+4</after>
26: <description></description>
27: </event>
28: <event>
29: <label>天の川銀河の誕生</label>
30: <!-- 現在から××年前を記載するときは before -->
31: <before unit="year">110E+8</before>
32: <description></description>
33: </event>
34: <event>
35: <label>太平洋戦争終結</label>
36: <!-- 西暦記載するときは dt で yyyy/mm/dd hh:mm:ss形式 -->
37: <dt>1945/8/15 00:00:00</dt>
38: <description></description>
39: </event>
40: <event>
41: <label>ハンムラビ王の即位</label>
42: <!-- 紀元前はマイナス表記 -->
43: <dt>-1792/1/1 00:00:00</dt>
44: <description></description>
45: </event>
46: <event>
47: <label>最初の恒星</label>
48: <!-- -->
49: <after unit="year">1.8E+8</after>
50: <description>2018年3月1日に、米アリゾナ州立大などの国際研究チームが発表した。</description>
準備:外部クラスなど
そこで、クラスファイル "pahooCalendar.php" を require_once し、オブジェクトを生成する。
解説:イベント・ファイルを読み込み、ソートする
249: /**
250: * イベント・ファイルを読み込み、ソートする
251: * @param string $fname イベント・ファイル名
252: * @param array $caldb イベントを格納する配列
253: * @param array $caption キャプションを格納する配列
254: * @return bool TRUE/FALSE
255: */
256: function readDB($fname, &$caldb, &$caption) {
257: $pcl = new pahooCalendar(); //pahooCalendarクラス
258: $pcl->setLanguage('jp');
259:
260: $jd_end = $pcl->Gregorian2JD(date('Y') + 1, 1, 1, 0, 0, 0); //今年の最後
261: $dd = 365 + date('L'); //1年の日数
262: $res = FALSE;
263:
264: //イベント・ファイル読み込み
265: if (file_exists($fname)) {
266: $xml = simplexml_load_file($fname);
267: //キャプション
268: if (isset($xml->caption->label)) {
269: $caption['label'] = isset($xml->caption->label) ? (string)$xml->caption->label : '宇宙カレンダー';
270: $caption['description'] = isset($xml->caption->description) ? (string)$xml->caption->description : '宇宙誕生から現在までを1年に圧縮';
271: }
272: //開始
273: if (isset($xml->start->before)) {
274: $start = (double)$xml->start->before;
275: $unit = ($dd * 24 * 60 * 60) / $start; //1秒当たり年数
276: $cnt = 0;
277: $caldb[$cnt]['label'] = (string)$xml->start->label;
278: $ss = $start * $unit;
279: list($caldb[$cnt]['dt'], $caldb[$cnt]['fmt']) = sigcalendar($ss);
280: $cnt++;
281: }
282: //イベント読み込み
283: foreach ($xml->event as $event) {
284: $caldb[$cnt]['label'] = (string)$event->label;
285: if (isset($event->before)) {
286: $ss = ($start - (double)$event->before) * $unit;
287: } else if (isset($event->after)) {
288: $ss = (double)$event->after * $unit;
289: } else if (isset($event->dt)) {
290: sscanf((string)$event->dt, '%d/%d/%d %d:%d:%f', $year, $month, $day, $hour, $min, $sec);
291: $jd = $pcl->Gregorian2JD($year, $month, $day, $hour, $min, $sec);
292: $ss = ($start - ($jd_end - $jd) / $dd) * $unit;
293: } else {
294: $ss = 0;
295: }
296: //カレンダー計算
297: list($caldb[$cnt]['dt'], $caldb[$cnt]['fmt']) = sigcalendar($ss);
298: $cnt++;
299: }
300: $res = TRUE;
301: }
302: $pcl = NULL;
303:
304: //ソート
305: usort($caldb, function ($a, $b) {
306: if (! isset($a['dt'])) return NULL;
307: if (! isset($b['dt'])) return NULL;
308: return $a['dt'] > $b['dt'] ? (+1) : (-1);
309: });
310:
311: return $res;
312: }
個々のイベント要素を読み込む際は、年数の表記が before, after, dt によって場合分けを行い、宇宙誕生(startに記述)を基準点として、そこから何秒の距離にあるかを変数 $ss に代入する。
イベントを、基準点と、その距離に置換することで、宇宙史だけでなく、日本史や家族史のような、スケールの異なるカレンダーも作ることができる。
解説:カレンダー計算
196: /**
197: * カレンダー計算
198: * @param double $ss 秒数
199: * @return array(カレンダー,フォーマット)
200: */
201: function sigcalendar($ss) {
202: $yyyy = date('Y'); //今年の西暦年
203: $tt = (int)strtotime($yyyy .'/1/1 0:0:0') + (int)$ss;
204: $dt = date('m/d H:i:s', $tt);
205:
206: //01/01 00:00:01以前→ミリ秒まで
207: if (preg_match('/^01\/01 01:01:01/', $dt) > 0) {
208: $fmt = 'm/d H:i:s';
209: $dt = date($fmt, $tt);
210: $dt .= sprintf('.%03d', (($ss - floor($ss)) * 1000));
211: //01/01 4時以前→秒まで
212: } else if (preg_match('/^12\/31 0[0-4]./', $dt) > 0) {
213: $fmt = 'm/d H:i:s';
214: $dt = date($fmt, $tt);
215: //01/01→分まで
216: } else if (preg_match('/^01\/01/', $dt) > 0) {
217: $fmt = 'm/d H:i';
218: $dt = date($fmt, $tt);
219: //1月→時まで
220: } else if (preg_match('/^01/', $dt) > 0) {
221: $fmt = 'm/d H:00';
222: $dt = date($fmt, $tt);
223: //12/31 23:59:59以降→ミリ秒まで
224: } else if (preg_match('/^12\/31 23:59:59/', $dt) > 0) {
225: $fmt = 'm/d H:i:s';
226: $dt = date($fmt, $tt);
227: $dt .= sprintf('.%03d', (($ss - floor($ss)) * 1000));
228: //12/31 20時以降→秒まで
229: } else if (preg_match('/^12\/31 2/', $dt) > 0) {
230: $fmt = 'm/d H:i:s';
231: $dt = date($fmt, $tt);
232: //12/31→分まで
233: } else if (preg_match('/^12\/31/', $dt) > 0) {
234: $fmt = 'm/d H:i';
235: $dt = date($fmt, $tt);
236: //12月→時まで
237: } else if (preg_match('/^12/', $dt) > 0) {
238: $fmt = 'm/d H:00';
239: $dt = date($fmt, $tt);
240: //それ以前→日まで
241: } else {
242: $fmt = 'm/d';
243: $dt = date($fmt, $tt);
244: }
245:
246: return array($dt, $fmt);
247: }
そこで、一定の境界条件を設け、カレンダーの時分秒を表示しなかったり、逆にミリ秒まで表示するようにした。
これを行うのがユーザー関数 sigcalendar である。
解説:データベースに表示用フラグを立てる
314: /**
315: * データベースに表示用フラグを立てる:全部
316: * @param array $caldb データベース
317: * @param int $ti マークしたい時刻(省略時は現在時刻)
318: * @return なし
319: */
320: function checkDB_all(&$caldb, $ti=0) {
321: if ($ti == 0) $ti = time(); //省略時
322:
323: $key = 0;
324: $flag = (-1);
325: foreach ($caldb as $rec) {
326: if (isset($rec['dt'])) {
327: $t0 = date($rec['fmt'], $ti);
328: if ($rec['dt'] < $t0) {
329: $caldb[$key]['flag'] = $flag;
330: } else if ($flag == (-1)) {
331: $flag++;
332: $caldb[$key]['flag'] = $flag;
333: $flag++;
334: } else {
335: $caldb[$key]['flag'] = $flag;;
336: }
337: $key++;
338: }
339: }
340: }
342: /**
343: * データベースに表示用フラグを立てる:同じ月
344: * @param array $caldb データベース
345: * @param int $ti マークしたい時刻(省略時は現在時刻)
346: * @return なし
347: */
348: function checkDB_month(&$caldb, $ti=0) {
349: if ($ti == 0) $ti = time(); //省略時
350: $t1 = date('m', $ti);
351:
352: $flag = (-2);
353: $key = 0;
354: foreach ($caldb as $rec) {
355: if (isset($rec['dt'])) {
356: $t0 = date($rec['fmt'], $ti);
357: if ($rec['dt'] < $t0) {
358: $caldb[$key]['flag'] = $flag;
359: } else if ($flag == (-2)) {
360: $caldb[$key]['flag'] = 0;
361: $flag = (+2);
362: } else {
363: $caldb[$key]['flag'] = $flag;
364: }
365: if (preg_match('/(^\d{2})/iu', $rec['dt'], $arr) > 0) {
366: if (($arr[1] == $t1) && ($caldb[$key]['flag']) != 0) {
367: $caldb[$key]['flag'] = (-1);
368: }
369: }
370: $key++;
371: }
372: }
373: }
375: /**
376: * データベースに表示用フラグを立てる:「今ここ」と前後2件ずつ
377: * @param array $caldb データベース
378: * @param int $ti マークしたい時刻(省略時は現在時刻)
379: * @return なし
380: */
381: function checkDB_now(&$caldb, $ti=0) {
382: if ($ti == 0) $ti = time(); //省略時
383:
384: $flag = (-2);
385: $key = 0;
386: foreach ($caldb as $rec) {
387: if (isset($rec['dt'])) {
388: $t0 = date($rec['fmt'], $ti);
389: if ($rec['dt'] < $t0) {
390: $caldb[$key]['flag'] = $flag;
391: $key++;
392: } else if ($flag == (-2)) {
393: $flag++;
394: for ($i = $key - 2; $i < $key; $i++) {
395: if (isset($caldb[$i]['label'])) $caldb[$i]['flag'] = $flag;
396: }
397: $flag++;
398: $i = $key;
399: if (isset($caldb[$i]['label'])) $caldb[$i]['flag'] = $flag;
400: $flag++;
401: $key++;
402: $caldb[$key]['flag'] = $flag;
403: $key++;
404: if (isset($caldb[$key]['label'])) $caldb[$key]['flag'] = $flag;
405: $key++;
406: $flag++;
407: } else {
408: $caldb[$key]['flag'] = $flag;
409: $key++;
410: }
411: }
412: }
413: }
こららを処理するのが、ユーザー関数 checkDB_all, checkDB_month, checkDB_now である。
解説:宇宙カレンダーを作成
433: /**
434: * 宇宙カレンダーを作成:テーブル形式
435: * @param array $caldb データベース
436: * @param array $caption キャプション
437: * @return string 表示用コンテンツ
438: */
439: function makeCosmicCalendar_table($caldb, $caption) {
440: $outstr =<<< EOT
441: <table class="stripe">
442: <caption>{$caption['label']}</caption>
443: <tr><th>日時</th><th>イベント</th></tr>
444:
445: EOT;
446:
447: foreach ($caldb as $rec) {
448: if ($rec['flag'] >= (-1) && $rec['flag'] <= (+1)) {
449: $mark = ($rec['flag'] == 0) ? ' ⏱' : '';
450: $outstr .=<<< EOT
451: <tr>
452: <td>{$rec['dt']}$mark</td>
453: <td>{$rec['label']}</td>
454: </tr>
455:
456: EOT;
457: }
458: }
459: $outstr .=<<< EOT
460: </table>
461:
462: EOT;
463: return $outstr;
464: }
415: /**
416: * 宇宙カレンダーを作成:テキスト形式
417: * @param array $caldb データベース
418: * @param array $caption キャプション
419: * @return string 表示用コンテンツ
420: */
421: function makeCosmicCalendar_text($caldb, $caption) {
422: $outstr = "<hr />■{$caption['label']}({$caption['description']})<br />\n";
423: foreach ($caldb as $rec) {
424: if ($rec['flag'] >= (-1) && $rec['flag'] <= (+1)) {
425: $outstr .= $rec['dt'] . ' - ' . $rec['label'];
426: if ($rec['flag'] == 0) $outstr .= '←いまココ';
427: $outstr .= "<br />\n";
428: }
429: }
430: return $outstr;
431: }
参考サイト
- コズミックカレンダー:高校生のためのおもしろ歴史教室
- 地球人類学:文化人類学解放講座(2016年度ブログ版)
アメリカの天文学者で作家の故カール・セーガン氏が考案したとされ、パパぱふぅは学生時代、セーガン氏が進行担当したテレビ番組「コスモス」や、来日した際の講演などを聞き、当時は電卓で計算し、ノートに記入したものだ。
今回は、PHPを使い、あらかじめ用意した年表データを宇宙カレンダーに変換し、表示するプログラムを作る。なお、年表データを、たとえば日本史や家族史に置き換えれば、オリジナルの宇宙カレンダーを作ることができる。
(2023年10月15日)sigcalendar()のbug-fix, pahooInputData導入
(2022年12月30日)1月は時分まで表示するようにした,cosmicCalendar.xml更新
(2022年7月21日)バグ修正,cosmicCalendar.xml更新