みみぺんブログ

WEBデザイナー、エンジニア、プログラマー向けの記事を投稿します

JavaScriptで日付セレクトボックスを作ろう!~うるう年も考慮してみよう!~

うるう年はどうやって計算するの?JavaScriptで作る日付セレクトボックスの作り方

はじめに

こんにちは、かずん(@kazoonLab)です。

前回の記事では、JavaScriptを使って年齢・日付を入力できるセレクトボックスを作りました。

前回のセレクトボックスは、存在しない日付が入力可能でした。今回は、そのような日付を取り除く仕組みを作っていきます。

今回作成するセレクトボックスはこちらです。実際の挙動を確かめてみてください。

See the Pen KKPvrKJ by kazoonLab (@kazoonLab) on CodePen.



かずん

この記事を読むと、閏年にも対応した日付セレクトボックスが作れるようになるよ!



こんな人に読んで欲しい

・Webコーダーの方

・フォームを自作したい方

・セレクトボックスのソースコードを短く書きたい方

・年月日(日付)のチェック方法を知りたい方

・年月日(日付)を扱うセレクトボックスを作りたい方


閏年(うるうどし)であるかチェックする

突然ですが、世の中には「閏年(うるうどし)」というものがあります。夏季オリンピックの年は2月が1日多くなるってやつですね。

他方、閏年じゃない年を「平年」と呼びます。当然、今年2019年は平年になります。

国立天文台のページでは、閏年は以下のように定義されています。

1. 西暦年号が4で割り切れる
2. 1.の例外として、西暦年号が100で割り切れて400で割り切れない年は平年とする

要するに、普通の4の倍数の年はうるう年でいいけど、2100年とか2200年は平年として扱うということですね。

また、シドニーオリンピックのあった2000年は100でも400でも割り切れるため、閏年になります。

ここで、年齢を引数にとって、それが閏年であるかチェックする関数を書いてみます。(ちなみに、閏年は英語で「leap year」というそうです。なぜ跳ねるのか)

【JavaScript】

const isLeapYear = year => (year % 4 === 0) && (year % 100 !== 0) || (year % 400 === 0);



一行で書くと、上記のようになります。コンソールで確かめると、以下のようになります。

【JavaScript】

isLeapYear(2001);  // --> false
isLeapYear(2012);  // --> true
isLeapYear(1800);  // --> false
isLeapYear(2000);  // --> true

各月の日数を配列で表現する

前回の記事のチェックボックスは、for文で決められた分だけオプションを生成していました。今回あり得ない日付を削除・閏年を考慮するために、生成する仕組みを変える必要があります。

例えば、1月は31日、11月は30日というように、各月の日数はそれぞれ異なります。なので、各月の日数を、配列で表現してみましょう。

【JavaScript】

const datesOfYear = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];



2月はうるう年の影響を受けるので、チェック関数を通してみます。

【JavaScript】

const today = new Date();
const year = today.getFullYear();
const datesOfFebruary = isLeapYear(year) ? 29 : 28;
const datesOfYear= [31, datesOfFebruary, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];



2019年現在はうるう年ではないため、isLearYear(year) はfalseが返ります。よって上記コードをコンソールで確認すると、datesOfYearには[31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] という配列が入ります。

セレクトボックスを改良する

それでは、画面ロード時に今日の日付が表示されているセレクトボックスを作ってみましょう。

【HTML】

<select id="year" name="year"></select>
<select id="month" name="month"></select>
<select id="date" name="date"></select>


【JavaScript】

(function() {
  const isLeapYear = year => (year % 4 === 0) && (year % 100 !== 0) || (year % 400 === 0);
  const today = new Date();
  const thisYear = today.getFullYear();
  const thisMonth = today.getMonth() + 1;
  const thisDate = today.getDate();
  const datesOfFebruary = isLeapYear(year) ? 29 : 28;
  const datesOfYear= [31, datesOfFebruary, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];

  const createOption = (id, startNum, endNum, current) => {
    const selectDom = document.getElementById(id);
    let optionDom = '';
    for (let i = startNum; i <= endNum; i++) {
      if (i === current) {
        option = '<option value="' + i + '" selected>' + i + '</option>';
      } else {
        option = '<option value="' + i + '">' + i + '</option>';
      }
      optionDom += option;
    }
    selectDom.insertAdjacentHTML('beforeend', optionDom);
  }

  createOption('year', 1900, thisYear, thisYear);
  createOption('month', 1, 12, thisMonth);
  createOption('date', 1, datesOfYear[thisMonth - 1], thisDate);
})()



<option> を生成する仕組み自体は、前回と変わりません。日のオプションを生成するときの範囲を、datesOfYear配列から取得しています。

今のソースのままだと、年・月を変更した時、日のオプションの個数が変化しません。そこで、以下の仕様にそって、セレクトボックスの中身を変化させてみましょう。

1. 「年」を変えた際、「1月1日」にリセットする。
2. 「月」を変えた際、「1日」にリセットする。
3. 1.と2.に関して、閏年のチェッカを通す。

セレクトボックスにイベントを設定する

まず、「月」を変えたときのイベントを設定しましょう。「月」が変わった際、月ごとに日数が異なるため、オプションを更新する必要があります。一方、「年」が変わるわけではないため、上記の配列自体を更新する必要はないですね。

上記より、「月」を変えたときのイベントは、以下のようになります。

【javascript】

const monthBox = document.getElementById('month');
const dateBox = document.getElementById('date');
monthBox.addEventListener('change', e => {
    monthBox.innerHTML = '';
    const updatedMonth = e.target.value;
    createOption('date', 1, datesOfYear[updatedMonth - 1], 1);
});



続いて、「年」を変えたときのイベントを設定しましょう。「年」が変わった際、その年が閏年かをチェックする必要があります。チェックし終わったら、日数の配列を更新し、オプションも更新してあげましょう。

上記より、「年」を変えたときのイベントは、以下のようになります。

【javascript】

const yearBox = document.getElementById('year');
const monthBox = document.getElementById('month');
const dateBox = document.getElementById('date');

yearBox.addEventListener('change', e => {
    monthBox.innerHTML = '';
    dateBox.innerHTML = '';
    const updatedYear = e.target.value;
    const datesOfFebruary = isLeapYear(updatedYear) ? 29 : 28;
    const datesOfYear = [31, datesOfFebruary, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];

    createOption('month', 1, 12, 1);
  createOption('date', 1, datesOfYear[0], 1);
});



これで、「年」を操作するイベントを設定できました。

あらためて、完全版のセレクトボックスはこちらになります。

See the Pen KKPvrKJ by kazoonLab (@kazoonLab) on CodePen.



また、動きは仮のHTMLにjsを読み込むか、codepenなどのサービスから確認できるかと思います。ぜひ試してみてください。

まとめ

前回・今回の記事で、JavaScriptを使ったセレクトボックスの作り方をご紹介しました。

セレクトボックスの他にも、JavaScriptで様々なDOMの制御を行うことができます。

今別のDOM操作に関しても今後触れていければと思います。是非読んでみてください!!

最後までご覧いただきありがとうございます。

この記事がいいなっと思ったら読者登録をお願いいたします♪



【ツイッターでは主に、仕事や技術系の内容をつぶやいています】 技術者の方ともっと繋がりたいっす!お気軽にフォローもお願いします!
かなきち(@kanakichi0801)
かずん(@kazoonLab)