【jQuery】日付選択のselectボックスで年月ごとに日を制御する

こんにちは、めぐたんです。今回はフォームのマークアップに関する備忘録をお届けします。

フォーム上の「生年月日」の項目は、selectタグを使ってプルダウン形式で選ばせる形が多いと思います。ただし、その際「2月30日」とか「6月31日」といった存在しない日付が選べると困ってしまいますよね。さらにいうと2月はうるう年か否かでも最終日が変わります。

これを解決するため、jQueryでの簡単な制御を試してみました。

基本のソースコードは下記ページを参照させていただいています!
javascriptでありえない日付をselectで選択させない制御

本記事では、内容の理解のために調べたことなども交えながらご紹介します。

実装したソースコードはこちら

まず初めに完成形のソースコードを記載します。

HTML

<input name="birth01" type="text" class="js-changeYear"> 年
<select name="birth02" class="js-changeMonth">
  <option value="1">1</option>
  <option value="2">2</option>
  <option value="3">3</option>
  <!-- ...省略。1月~12月まで記述します -->
  <option value="12">12</option>
</select> 月
<select name="birth03" class="js-changeDay">
  <option value="1">1</option>
  <option value="2">2</option>
  <option value="3">3</option>
  <!-- ...省略。1日~31日まで記述します -->
  <option value="29">29</option>
  <option value="30">30</option>
  <option value="31">31</option>
</select> 日

JS

(function($){
  function formSetDay(){
    var lastday = formSetLastDay($('.js-changeYear').val(), $('.js-changeMonth').val());
    var option = '';
    for (var i = 1; i <= lastday; i++) {
      if (i === $('.js-changeDay').val()){
        option += '<option value="' + i + '" selected="selected">' + i + '</option>n';
      }else{
        option += '<option value="' + i + '">' + i + '</option>n';
      }
    }
    $('.js-changeDay').html(option);
  }
  function formSetLastDay(year, month){
    var lastday = new Array('', 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
    if ((year % 4 === 0 && year % 100 !== 0) || year % 400 === 0){
      lastday[2] = 29;
    }
    return lastday[month];
  }
  $('.js-changeYear, .js-changeMonth').change(function(){
    formSetDay();
  });
})(jQuery);


デモ

生年月日

上記ソースコードのデモがこちら。
いかがでしょうか?月ごとの最終日の制御や、うるう年判定もうまく動くようになりました。

JSの記述内容を紐解いてみる

ここからは、ご紹介したJSの記述内容を紐解いてみます。
入力画面上で「年」「月」に変更が加えられたタイミングで2種類の関数が動作しています。

  • formSetDay関数
  • formSetLastDay関数

それぞれの動きを図解してみるとこんな感じ。

記述内容の図解

記号 動作
A 「年」「月」に変更が加えられたらformSetDay関数を呼び出し
B formSetDay関数はまずformSetLastDayに渡された年月の最終日を聞く
C formSetLastDayが日付を判定し、formSetDayに最終日を返す
D formSetDayは渡された最終日をもとに、入力画面の「日」を生成しなおして表示

月の最終日・うるう年の判定のポイントとなるのはB~Cで動作しているformSetLastDay関数の部分。
それではこの関数について、さらに記述をきちんと見てみましょう。

formSetLastDay関数を詳しく見てみた

formSetLastDay関数は先ほどの図解のとおり、渡された「年」「月」に対して最終日を割り出して、最終日の数値を返してくれる関数です。

// 完成形のソースから「formSetLastDay」関数部分を抜粋
function formSetLastDay(year, month){
  var lastday = new Array('', 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
  if ((year % 4 === 0 && year % 100 !== 0) || year % 400 === 0){
    lastday[2] = 29;
  }
  return lastday[month];
}

2行目、変数「lastday」に配列形式で月の最終日の数値を格納しています。

var lastday = new Array('', 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);

配列の添字は0はじまりなので最初は空欄('')、以降は「1月の最終日31、2月の最終日28、3月の最終日31…」といった具合です。

続いてうるう年の判定をして、「2月分の最終日として格納する数字は28でOKか?」を確認します。
うるう年の定義は下記です。

  1. 「4で割り切れる」年はうるう年(例:2012年、2016年、2020年)
  2. 「100で割り切れる」年はうるう年ではない(例:2100年、2200年)
  3. 2の例外として、「400で割り切れる」年はうるう年(例:2000年、2400年)

うるう年判定のフローチャート

これをもとに下記の条件文ができあがり、渡された「年」が当てはまる場合は「lastday」の添字2(=2月分の最終日)を29にセットし直します。

if ((year % 4 === 0 && year % 100 !== 0) || year % 400 === 0){
  lastday[2] = 29;
}

ここまでで、月の最終日を割り出すための処理準備が整いました!
あとは「lastday」変数の中で渡された「月」の添字にあてはまる日付を返します。

return lastday[month];

例:monthが7だったらlastday[7]を参照して「31」を返す

これでformSetLastDay関数の仕事は完了です。あとは図解のDに進み、formSetDay関数が「日」のoptionを再生成してくれます。

まとめ

今回は、参考にさせていただいたソースコードを見て「うるう年の条件分岐ってこう書くんだ?そもそもうるう年の定義って何だっけ…」という疑問が生まれたことから、記述内容に少し踏み込んでみました。

同じような疑問を持った方や、jQuery初心者の方にも仕組みを解読してもらえる記事になってるとよいな~と思います!以上、めぐたんでした。

');