PHPで元号年月日入力(プルダウン方式)

(1/1)
PHPでプルダウンメニューを使って元号(明治、大正‥‥)年月日を入力するフォームを作る。元号の切り替わり(例:昭和64年1月7日の翌日は平成元年1月8日)に注意し、存在しない年月日は入力できないようにする。また、日数は大の月と小の月によって変わるようにし、とくに閏年の2月の入力に気をつける。

(2021年5月10日)元号変更年における月・日の選択動作改善
(2021年4月24日)PHP8対応,リファラ・チェック改良

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

PHPで元号年月日入力

目次

サンプル・プログラムのダウンロード

圧縮ファイルの内容
gengo2gregorian.phpサンプル・プログラム本体。

解説:元号の開始と終了

  37: //元号=西暦一覧
  38: $eraTable = array(
  39:     '明治'   => array('from'=>'18680125', 'to'=>'19120729'),
  40:     '大正'   => array('from'=>'19120730', 'to'=>'19261224'),
  41:     '昭和'   => array('from'=>'19261225', 'to'=>'19890107'),
  42:     '平成'   => array('from'=>'19890108', 'to'=>'20190430'),
  43:     '令和'   => array('from'=>'20190501', 'to'=>'29991231')
  44: );

プログラムの部品は、いままで作ってきた「PHPで日本語対応dateを作る」「PHPで年月日を入力」の寄せ集めである。

あらたに作るのは、元号の切り替わり(例:昭和64年1月7日の翌日は平成元年1月8日)に注意して年月日のプルダウンを制御する部分である。そのために、あらかじめ西暦と元号の関係表をグローバル変数 $eraTable に用意しておく。

解説:西暦年月日を元号に変換

 180: /**
 181:  * 西暦年月日を元号に変換
 182:  * @param   int $year  西暦年
 183:  * @param   int $month 月
 184:  * @param   int $day   日
 185:  * @return  array era=元号, year=元号年, month=月, day=日
 186: */
 187: function ad2era($year, $month, $day) {
 188:     global $eraTable;
 189: 
 190:     $res = array('era'=>'', 'year'=>$year, 'month'=>$month, 'day'=>$day);
 191:     $yyyymmdd = sprintf('%04d%02d%02d', $year, $month, $day);
 192: 
 193:     foreach ($eraTable as $era=>$val) {
 194:         if ($yyyymmdd <$val['to']) {
 195:             $res['era'] = $era;
 196:             $y = (int)substr($eraTable[$eraset['era']]['from'], 0, 4);
 197:             $res['year'] = $year - $y + 1;
 198:             break;
 199:         }
 200:     }
 201: 
 202:     return $res;
 203: }

ユーザー関数 ad2era は、西暦年月日を引数とし、グローバル変数 $eraTable を参照し、対応する元号・元号年月日を返す。

解説:元号を西暦年月日に変換

 205: /**
 206:  * 元号を西暦年月日に変換
 207:  * @param   array eraset  元号年月日 era=元号, year=元号年, month=月, day=日
 208:  * @return  array year=西暦年, month=月, day=日
 209: */
 210: function era2ad($eraset) {
 211:     global $eraTable;
 212: 
 213:     $res = array('year'=>$eraset['year'], 'month'=>$eraset['month'], 'day'=>$eraset['day']);
 214:     $yyyymmdd = $eraTable[$eraset['era']]['from'];
 215:     $year = (int)substr($yyyymmdd, 0, 4);
 216:     $res['year']  = $eraset['year'+ $year - 1;
 217: 
 218:     return $res;
 219: }

ユーザー関数 era2ad は、ad2era の逆関数である。

解説:指定した元号の年数・月数・日数

 221: /**
 222:  * 指定した元号の年数・月数・日数を返す
 223:  * @param   array $eraset 元号年月日 era=元号, year=元号年, month=月, day=日
 224:  * @return  array yy=年数, mm=月数, dd=日数
 225: */
 226: function getYymmddInEra($eraset) {
 227:     global $eraTable;
 228: 
 229: 
 230:     $res = era2ad($eraset);     //元号を西暦年月日に変換
 231:     $year = $res['year'];
 232: 
 233:     //年数
 234:     $y0 = (int)substr($eraTable[$eraset['era']]['from'], 0, 4);
 235:     $y1 = (int)substr($eraTable[$eraset['era']]['to'],   0, 4);
 236:     $yy = $y1 - $y0 + 1;
 237:     if ($eraset['year'> $yy) {
 238:         $eraset['year'] = 1;
 239:         $res = era2ad($eraset);     //元号を西暦年月日に変換
 240:         $year = $res['year'];
 241:     }
 242: 
 243:     //月数
 244:     if ($year == $y0) {
 245:         $m0 = (int)substr($eraTable[$eraset['era']]['from'], 4, 2);
 246:         $m1 = 12;
 247:         if ($eraset['month'< $m0)  $eraset['month'] = $m0;
 248:     } else if ($year == $y1) {
 249:         $m0 = 1;
 250:         $m1 = (int)substr($eraTable[$eraset['era']]['to'], 4, 2);
 251:         if ($eraset['month'> $m1$eraset['month'] = $m1;
 252:     } else {
 253:         $m0 = 1;
 254:         $m1 = 12;
 255:     }
 256: 
 257:     //日数
 258:     $ym0 = substr($eraTable[$eraset['era']]['from'], 0, 6);
 259:     $ym1 = substr($eraTable[$eraset['era']]['to'],   0, 6);
 260:     $yymm = sprintf('%04d%02d', $year, $eraset['month']);
 261: 
 262:     static $days = array(0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
 263:     $days[2] = isLeapYear($year? 29 : 28;     //閏年の判定
 264:     if ($yymm == $ym0) {
 265:         $d0 = (int)substr($eraTable[$eraset['era']]['from'], 6, 2);
 266:         $d1 = $days[$eraset['month']];
 267:         if ($eraset['day'< $d0)    $eraset['day'] = $d0;
 268:     } else if ($yymm == $ym1) {
 269:         $d0 = 1;
 270:         $d1 = (int)substr($eraTable[$eraset['era']]['to'], 6, 2);
 271:         if ($eraset['day'> $d1)   $eraset['day'] = $d1;
 272:     } else {
 273:         $d0 = 1;
 274:         $d1 = $days[$eraset['month']];
 275:     }
 276: 
 277:     return array('yy'=>array('from'=>1, 'to'=>$yy), 'mm'=>array('from'=>$m0, 'to'=>$m1), 'dd'=>array('from'=>$d0, 'to'=>$d1));
 278: }

たとえば「昭和64年」を選択した場合、月は「1月」だけ、日は「1~7日」までしか選択できないようにする。
そこで、引数として元号年月日を渡すと、年・月・日の範囲を配列で返すユーザー関数が getYymmddInEra である。
同時に、閏年のときは2月29日になるようにする。

解説:元号年月日をプルダウンメニューにする

 360: //プルダウンメニュー
 361:     $outstr = '';
 362:     $name = 'exec';
 363: //元号セレクタ
 364:     $outstr .=<<< EOT
 365: <select name="era" id="era" onChange="submit();">
 366: 
 367: EOT;
 368:     $eraset2['era'] = '';
 369:     foreach ($eraTable as $era=>$val) {
 370:         if ($era == $eraset['era']) {
 371:             $selected = 'selected';
 372:             $eraset2['era'] = $era;
 373:         } else {
 374:             $selected = '';
 375:         }
 376:         $outstr .=<<< EOT
 377: <option value="{$era}" {$selected}>{$era}</option>
 378: 
 379: EOT;
 380:     }
 381:     $outstr .=<<< EOT
 382: </select>
 383: 
 384: EOT;
 385: 
 386: //年号セレクタ
 387:     $outstr .=<<< EOT
 388: <select name="year" id="year" onChange="submit();">
 389: 
 390: EOT;
 391:     $eraset2['year'] = 0;
 392:     for ($yy = $res['yy']['from']; $yy <$res['yy']['to']; $yy++) {
 393:         if ($yy == $eraset['year']) {
 394:             $selected = 'selected';
 395:             $eraset2['year'] = $yy;
 396:         } else {
 397:             $selected = '';
 398:         }
 399:         $yn = ($yy == 1? '元' : $yy;
 400:         $outstr .=<<< EOT
 401: <option value="{$yy}" {$selected}>{$yn}</option>
 402: 
 403: EOT;
 404:     }
 405:     $outstr .=<<< EOT
 406: </select>年
 407: 
 408: EOT;
 409: 
 410: //月セレクタ
 411:     $outstr .=<<< EOT
 412: <select name="month" id="month" onChange="submit();">
 413: 
 414: EOT;
 415:     $eraset2['month'] = 1;
 416:     for ($mm = $res['mm']['from']; $mm <$res['mm']['to']; $mm++) {
 417:         if ($mm == $eraset['month']) {
 418:             $selected = 'selected';
 419:             $eraset2['month'] = $mm;
 420:         } else {
 421:             $selected = '';
 422:         }
 423:         $outstr .=<<< EOT
 424: <option value="{$mm}" {$selected}>{$mm}</option>
 425: 
 426: EOT;
 427:     }
 428:     $outstr .=<<< EOT
 429: </select>月
 430: 
 431: EOT;
 432: 
 433: //日セレクタ
 434:     $outstr .=<<< EOT
 435: <select name="day" id="day" onChange="submit();">
 436: 
 437: EOT;
 438:     $eraset2['day'] = 1;
 439:     for ($dd = $res['dd']['from']; $dd <$res['dd']['to']; $dd++) {
 440:         if ($dd == $eraset['day']) {
 441:             $selected = 'selected';
 442:             $eraset2['day'] = $dd;
 443:         } else {
 444:             $selected = '';
 445:         }
 446:         $outstr .=<<< EOT
 447: <option value="{$dd}" {$selected}>{$dd}</option>
 448: 
 449: EOT;
 450:     }
 451: 
 452:     $ad = era2ad($eraset2);     //元号を西暦年月日に変換
 453:     $outstr .=<<< EOT
 454: </select>日
 455: 
 456: <p>西暦 {$ad['year']} 年 {$ad['month']} 月 {$ad['day']} 日</p>
 457: 
 458: EOT;
 459: 
 460:     $body =<<< EOT

プルダウンメニューは、元号(era)、年(year)、月(month)、日(date)を別々のタグにする。

このプルダウンメニューが変化したら、JavaScript の onChange イベントで submit 駆動し、form 内容を送信するようにしている。これは元号(era)、年(year)、月(month)の場合も同様で、これを行うことで、元号・年・月・日を変更した際に再計算を行う。

ただし、いちいちサーバサイドで計算させることはサーバに負荷がかかるので、この処理は、本来はクライアントサイドでJavaScriptで行わせるのが良いだろう。JavaScriptによる処理については、「元号による年月日セレクタ」で紹介している。

参考サイト

参考書籍

表紙 元号って何だ?
著者 藤井 青銅
出版社 小学館
サイズ 新書
発売日 2019年02月01日頃
価格 880円(税込)
ISBN 9784098253395
元号に関する素朴な疑問に答える入門書。そしていまいちばん楽しめる元号本。多くの日本人は平成⇒昭和⇒大正⇒明治まで遡ることができても明治の一つ前の元号を言うことができない。だから元号というと難しく感じる人もいるが、じつはとても人間くさくて面白いものなのだ。本書では全部で247ある元号をいろいろなランキングを使って解説。またさまざまな元号由来のネーミングや全国の改元ゆかりの地などを紹介する。まったく新しい元号読み物!
 
(この項おわり)
header