LoginSignup
16
16

More than 3 years have passed since last update.

jQueryを使用して 閏年判定付き 生年月日フォーム をつくってみた

Last updated at Posted at 2019-11-21

1. はじめに

個人的に、何らかサイトの会員登録画面で生年月日を入力するとき、
存在しない月日(例えば 9月31日、2月30日、4月31日 など) が選択できてしまうことが 割とよくあります。

システム的にも、ユーザー的にも、存在しない月日は入力できない方が良いはずです。

さらに、閏年は2月29日までありますし、
今回は、その点も含めて 存在しない年月日を入力できないように セレクトボックスの選択肢を制御する方法を調べてみました。

2. 準備

作成にあたって、以下のツールを準備します。

  • テキストエディター
  • ブラウザ (ここではChromeを使用)

また、ライブラリーに jQueryを使用します。
jQueryのサイトからファイルの読み込み方を確認します。

3. 作成

作成した生年月日フォームのhtml・jsファイルの全体像とブラウザ画面を示します。

3-1. コーディング

以下に作成した html(main.html) と javascript(form.js) を示します。

main.htmlでは、jQueryライブラリーと"js/form.js"を呼び出しています。

main.html
<!DOCTYPE html>
<html lang="ja">
<head>

    <title>Form</title>

    <script
    src="https://code.jquery.com/jquery-3.4.1.slim.min.js"
    integrity="sha256-pasqAKBDmFT4eHoN2ndd6lN370kFiGUFyTiUHWhU7k8="
    crossorigin="anonymous"></script>
    <script type="text/javascript" src="js/form.js"></script>

</head>
<body>
        <li>
            <label for="birth">年月日: </label>
            <select id="year">
                <option value="0">----</option>
            </select><select id="month">
                <option value="0">--</option>
            </select><select id="date">
                <option value="0">--</option>
            </select></li>

</body>


main.htmlで呼び出している、form.jsの内容は以下の通りです。

form.js
$(function() {
    // 現在の年月日を取得
    var time = new Date();
    var year = time.getFullYear();
    var month = time.getMonth() + 1;
    var date = time.getDate();

    // 選択された年月日を取得
    var selected_year = document.getElementById("year").value;
    var selected_month = document.getElementById("month").value;

    // 年(初期): 1900〜現在の年 の値を設定
    for (var i = year; i >= 1900 ; i--) {
        $('#year').append('<option value="' + i + '">' + i + '</option>');
    }

    // 月(初期): 1~12 の値を設定
    for (var j = 1; j <= 12; j++) {
        $('#month').append('<option value="' + j + '">' + j + '</option>');
    }

    // 日(初期): 1~31 の値を設定
    for (var k = 1; k <= 31; k++) {
        $('#date').append('<option value="' + k + '">' + k + '</option>');
    }

    // 月(変更):選択された年に合わせて、適した月の値を選択肢にセットする
    $('#year').change(function() {
        selected_year = $('#year').val();

        // 現在の年が選択された場合、月の選択肢は 1~現在の月 に設定
        // それ以外の場合、1~12 に設定
        var last_month = 12;
        if (selected_year == year) {
            last_month = month;
        }
        $('#month').children('option').remove();
        $('#month').append('<option value="' + 0 + '">--</option>');
        for (var n = 1; n <= last_month; n++) {
            $('#month').append('<option value="' + n + '">' + n + '</option>');
        }
    });

    // 日(変更):選択された年・月に合わせて、適した日の値を選択肢にセットする
    $('#year,#month').change(function() {
        selected_year = $('#year').val();
        selected_month = $('#month').val();

        // 現在の年・月が選択された場合、日の選択肢は 1~現在の日付 に設定
        // それ以外の場合、各月ごとの最終日を判定し、1~最終日 に設定
        if (selected_year == year && selected_month == month ) {
            var last_date = date;
        }else{
            // 2月:日の選択肢は1~28日に設定
            // ※ ただし、閏年の場合は29日に設定
            if (selected_month == 2) {
                if((Math.floor(selected_year%4 == 0)) && (Math.floor(selected_year%100 != 0)) || (Math.floor(selected_year%400 == 0))){
                    last_date = 29;
                }else{
                    last_date = 28;
                }

            // 4, 6, 9, 11月:日の選択肢は1~30日に設定
            }else if(selected_month == 4 || selected_month == 6 || selected_month == 9 || selected_month == 11 ){
                last_date = 30;

            // 1, 3, 5, 7, 8, 10, 12月:日の選択肢は1~31日に設定
            }else{
                last_date = 31;
            }
        }

        $('#date').children('option').remove();
        $('#date').append('<option value="' + 0 + '">--</option>');
        for (var m = 1; m <= last_date; m++) {
            $('#date').append('<option value="' + m + '">' + m + '</option>');
        }
    });

});

3-2. 画面

ブラウザで表示される画面を示します。

スクリーンショット 2019-11-20 17.43.50.png

例1) 現在の年月日が 2019年11月20日として、ユーザーが 「年」に"2019"、「月」に"11" を選択した場合、日には選択肢として"1~20" が表示されます。
(2019年11月21日~2019年11月30日 は選択できない。)

スクリーンショット 2019-11-20 17.45.42.png

例2) ユーザーが、「年」に"2016"、「月」に"2" を選択した場合、「日」には選択肢として"1~29" が設定されます。

スクリーンショット 2019-11-20 17.43.12.png

See the Pen Form by Haruka Ogawa (@haruka0121) on CodePen.

4. 解説

form.js の処理内容を解説します。

4-1. 現在の年月日取得

セレクトボックスで 未来の年月日を選択できないように処理するため、
まず 現在の年月日を取得しておく必要があります。

new Date()で現在の日付オブジェクトを生成し、
そこから 現在の年月日の値をそれぞれ取得して、変数 yearmonthdateに入力します。


    // 現在の年月日を取得
    var time = new Date();
    var year = time.getFullYear();
    var month = time.getMonth() + 1;
    var date = time.getDate();

・日付オブジェクト 生成

new Date()を使用し、日付オブジェクトを生成します。
引数に何も指定しない場合、現在の日付オブジェクトが生成されます。

new Date();

今回、生成した日付オブジェクトは、変数timeに入力します。

・現在の年 取得

getFullYear() を使用し、指定した日付オブジェクトの「年」を取得します。

構文は以下の通りです。

日付オブジェクト.getFullYear();

今回は、日付オブジェクトとして 変数time を指定します。

・現在の月 取得

getMonth() を使用し、指定した日付オブジェクトの「月」を取得します。
getMonth()0~11で返されるため、値に +1 して使用します。

構文は以下の通りです。

// 0から11の値で返される
日付オブジェクト.getMonth() 

今回は、日付オブジェクトとして 変数time を指定します。

・現在の日 取得

getDate() を使用し、指定した日付オブジェクトの「日」を取得します。

構文は以下の通りです。

日付オブジェクト.getDate()

今回は、日付オブジェクトとして 変数time を指定します。

4-2. 選択された年月日取得

セレクトボックスで 存在しない日 や 未来の年月日 を選択できないようにするため、
「年」・「月」セレクトボックスで ユーザーが選択した値によって、「月」・「日」セレクトボックスの選択肢を設定します。

まず ここでは、「年」・「月」セレクトボックスで ユーザーが選択した値を取得します。

getElementByIdを使用し、ユーザーが選択した「年」・「月」の値を取得し、
それぞれ変数 selected_yearselected_monthに代入します。

    // 選択された年月日を取得
    var selected_year = document.getElementById("year").value;
    var selected_month = document.getElementById("month").value;

引数には、htmlで設定した「年」・「月」セレクトボックスのid名("year"・"month")を指定します。

構文は以下の通りです。

document.getElementById(id).value;

4-3. 年月日の選択肢設定(初期)

フォーム画面が表示された時点(初期)での、「年」「月」「日」セレクトボックスの選択肢を設定します。

・「年」の選択肢設定(初期)

「年」セレクトボックスは、1900~現在の年 の値を選択肢とします。
現在の年 は、変数 year に代入してあります。


    // 年(初期): 1900〜現在の年 を設定
    for (var i = year; i >= 1900 ; i--) {
        $('#year').append('<option value="' + i + '">' + i + '</option>');
    }

ループ処理を用いて、1900 ~ year の値を「年」の選択肢として生成します。

生成した値は、append()を用いて、「年」セレクトボックスに挿入します。

$(セレクタ).append(挿入コンテンツ);

ここでは、セレクタとして htmlで指定した「年」セレクトボックスの id名("year")を指定します

・「月」の選択肢設定(初期)

「月」セレクトボックスは、1~12 の値を選択肢とします。


    // 月(初期): 1~12 の値を設定
    for (var j = 1; j <= 12; j++) {
        $('#month').append('<option value="' + j + '">' + j + '</option>');
    }

ループ処理を用いて、1~12 の値を「月」の選択肢として生成します。

生成した値は、append()を用いて、「月」セレクトボックスに挿入します。
セレクタとして htmlで指定した「月」セレクトボックスの id名("month")を指定します

・「日」の選択肢設定(初期)

「日」セレクトボックスは、1~31 の値を選択肢とします。

    // 日(初期): 1~31 の値を設定
    for (var k = 1; k <= 31; k++) {
        $('#date').append('<option value="' + k + '">' + k + '</option>');
    }

ループ処理を用いて、1~31 の値を「日」の選択肢として生成します。

生成した値は、append()を用いて、「日」セレクトボックスに挿入します。
セレクタとして htmlで指定した「日」セレクトボックスの id名("date")を指定します

4-4. 月日の選択肢 変更

・「月」の選択肢 変更

未来の年月日が選択されないように、月の選択肢を変更します。

例えば、現在が2019年11月21日の場合、
ユーザーが「年」セレクトボックスで2019を選択したとき、「月」セレクトボックスの選択肢に 12 が表示されないようにします。

    // 月(変更):選択された年に合わせて、適した月の値を選択肢にセットする
    $('#year').change(function() {
        // 選択された年の値を取得する
        selected_year = $('#year').val();

        // 現在の年が選択された場合、月の選択肢は 1~現在の月 に設定
        // それ以外の場合、1~12 に設定
        var last_month = 12;
        if (selected_year == year) {
            last_month = month;
        }

        $('#month').children('option').remove();
        $('#month').append('<option value="' + 0 + '"></option>');

        for (var n = 1; n <= last_month; n++) {
            $('#month').append('<option value="' + n + '">' + n + '</option>');
        }
    });

  • change():「月」セレクトボックス 選択肢 変更処理 実行

change()を用いて、
「年」セレクトボックスで値が選択された時に、
「月」セレクトボックス 選択肢 変更処理が実行されるように設定します。

$(セレクタ).change(ファンクション)

ここでは、セレクタとして htmlで指定した「年」セレクトボックスの id名("year")を指定します。

ファンクションには、「月」セレクトボックスの選択肢を変更する処理を記述します。

  • val() :「年」セレクトボックスの選択された値取得

val()を用いて、
選択された「年」の値を取得します。

$(セレクタ).val() 

ここでは、セレクタとして htmlで指定した「年」セレクトボックスの id名("year")を指定します。

  • 「月」選択肢 の値範囲 決定

条件処理を用いて、
生成する「月」セレクトボックスの選択肢の値の範囲を決定します。

「年」セレクトボックスで
現在の年 が選択された場合、「月」セレクトボックスの選択肢は 1 ~ 現在の月
それ以外の場合、「月」セレクトボックスの選択肢は 1~12
に設定します。

  • remove() :「月」セレクトボックスの選択肢 削除

remove()を用いて、
設定されている「月」セレクトボックスの選択肢の値を削除し、初期化します。

$(セレクタ).remove();
  • append() :「月」セレクトボックス 未選択時 の値 挿入

append()を用いて、
「月」セレクトボックス 未選択時 の値 を挿入します。

$(セレクタ).append(挿入コンテンツ);

ここでは、セレクタとして htmlで指定した「月」セレクトボックスの id名("month")を指定します。

挿入コンテンツには、「月」セレクトボックス未選択時 の値として"--"が 表示されるように設定します。

  • 「月」セレクトボックス の選択肢の値 生成・変更

ループ処理を用いて、「月」の選択肢の値を生成します。
生成した値はappend()を用いて、「月」セレクトボックスに挿入します。

・「日」の選択肢 変更

存在しない年月日が選択されないように、「日」セレクトボックスの選択肢を変更します。

具体的には、
現在の年月日を確認し、未来の年月日が選択できないよう、「日」セレクトボックスの選択肢を変更します。
さらに、閏年や各月の正しい最終日を考慮し、存在しない日(9月31日2月30日4月31日 など )も選択できないように処理します。

    // 日(変更):選択された年・月に合わせて、適した日の値を選択肢にセットする
    $('#year,#month').change(function() {
        selected_year = $('#year').val();
        selected_month = $('#month').val();

        // 現在の年・月が選択された場合、日の選択肢は 1~現在の日付 に設定
        // それ以外の場合、各月ごとの最終日を判定し、1~最終日 に設定
        if (selected_year == year && selected_month == month ) {
            var last_date = date;
        }else{
            // 2月:日の選択肢は1~28日に設定
            // ※ ただし、閏年の場合は29日に設定
            if (selected_month == 2) {
                if((Math.floor(selected_year%4 == 0)) && (Math.floor(selected_year%100 != 0)) || (Math.floor(selected_year%400 == 0))){
                    last_date = 29;
                }else{
                    last_date = 28;
                }

            // 4, 6, 9, 11月:日の選択肢は1~30日に設定
            }else if(selected_month == 4 || selected_month == 6 || selected_month == 9 || selected_month == 11 ){
                last_date = 30;

            // 1, 3, 5, 7, 8, 10, 12月:日の選択肢は1~31日に設定
            }else{
                last_date = 31;
            }
        }

        $('#date').children('option').remove();
        $('#date').append('<option value="' + 0 + '">--</option>');

        for (var m = 1; m <= last_date; m++) {
            $('#date').append('<option value="' + m + '">' + m + '</option>');
        }
    });
  • change():「日」セレクトボックス 選択肢 変更処理 実行

change()を用いて、
「年」・「月」セレクトボックスで値が選択された時に、
選択肢 変更処理が実行されるように設定します。

$(セレクタ).change(ファンクション)

ここでは、セレクタとして htmlで指定した「年」・「月」セレクトボックスの id名("year", "month")を指定します。

ファンクションには、「日」セレクトボックスの選択肢を変更する処理を記述します。

  • val() :「年」・「月」セレクトボックスの選択された値取得

val()を用いて、
選択された「年」・「月」の値を取得します。

$(セレクタ).val() 

ここでは、セレクタとして htmlで指定した「年」・「月」セレクトボックスの id名("year", "month")を指定します。

  • 「日」選択肢 の値範囲 決定

条件処理を用いて、
生成する「日」セレクトボックスの選択肢の値の範囲を決定します。

ここでは、「年」・「月」セレクトボックスで、
それぞれ 現在の年・月 が選択された場合、「日」セレクトボックスの選択肢は 1~現在の日付
それ以外の場合、「月」セレクトボックスの選択肢は 1~月の最終日
に設定します。

月の最終日は、閏年や月で異なるため、
さらに細かく条件を分岐させて値の範囲を設定します。

選択された「月」の値が2月の場合、
「日」セレクトボックスの選択肢の範囲は
閏年であれば1~29日、
閏年ではなければ1~28日に設定します。

※ 以下の場合、閏年と判定する。
・西暦を4で割り切れ
て、かつ100で割り切れない
・西暦を400で割り切れる

選択された「月」の値が4, 6, 9, 11月の場合、
「日」セレクトボックスの選択肢の範囲は 1~30日に設定します。

選択された「月」の値が1, 3, 5, 7, 8, 10, 12月の場合、
「日」セレクトボックスの選択肢の範囲は 1~31日に設定します。

  • remove() :「日」セレクトボックスの選択肢 削除

remove()を用いて、
設定されている「日」セレクトボックスの選択肢の値を削除し、初期化します。

$(セレクタ).remove();
  • append() :「日」セレクトボックス 未選択時 の値 挿入

append()を用いて、
「日」セレクトボックス 未選択時 の値 を挿入します。

$(セレクタ).append(挿入コンテンツ);

ここでは、セレクタとして htmlで指定した「日」セレクトボックスの id名("date")を指定します。

挿入コンテンツには、「日」セレクトボックス未選択時 の値として"--"が 表示されるように設定します。

  • 「日」セレクトボックス の選択肢の値 生成・変更

ループ処理を用いて、「日」の選択肢の値を生成します。
生成した値はappend()を用いて、「日」セレクトボックスに挿入します。

5. おわりに

今回は、存在しない年月日が入力できない 閏年判定付き 生年月日フォームを作成しました。

jQueryを使用すると、簡単にhtml要素を変更できるので、生年月日フォーム以外でも活用できそうです。

追記

「年」の値が選択されたら「月」、
「年」・「月」の値が選択されたら「日」 の選択肢が再設定される処理の流れになっていますが、
ユーザーが「年」より先に「月」or「日」、または「月」より先に「日」の値を選択していた場合、
選択肢の再設定処理で、ユーザーの選択していた値が初期化されてしまいます。

もっと理想を言えば、再設定処理がされても、ユーザーが選択していた値を保持できれば 良いなと思います。

参考情報

・JavaScript 日本語リファレンス
http://js.studio-kingdom.com/

・nkmrkisk.com:【js】jQuery or jsで生年月日入力formを自動生成するサンプルコード
https://nkmrkisk.com/archives/1153

・yuya4の備忘録:【JavaScript】【jquery】セレクトボックスでのうるう年計算
http://yu-ya4.hatenablog.com/entry/2015/07/03/195409

・ITの隊長のブログ:【jQuery】年と月からうるう年も計算した日を出力する
https://www.aipacommander.com/entry/2015/08/11/155210

・jQuery CDN – Latest Stable Versions
https://code.jquery.com/

16
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
16