カレンダー一覧

JavaScriptで今月のカレンダーを作る方法

JavaScriptのDateオブジェクトを使って、今月分のカレンダーを生成する方法を紹介します。

カレンダー系のライブラリは数多くありますが、ライブラリに頼らず自作することも十分可能です。

HTML・CSSを作成

最初に、カレンダーの土台となるHTMLとCSSを作成しておきます。

<table class="calendar">
  <caption>
    <!-- スクリプトで中身を生成 -->
  </caption>
  <thead>
    <tr>
      <th>Sun</th>
      <th>Mon</th>
      <th>Tue</th>
      <th>Wed</th>
      <th>Thu</th>
      <th>Fri</th>
      <th>Sat</th>      
    </tr>
  </thead>
  <tbody>
    <!-- スクリプトで中身を生成 -->
  </tbody>
</table>
/* カレンダー全体の設定 */
.calendar {
  border-collapse: collapse;
}

.calendar th,
.calendar td {
  width: 40px;
  height: 25px;
  border: 1px solid #000;
  text-align: center;
}

/* 日曜日 */
.calendar th:nth-child(1),
.calendar td:nth-child(1) {
  color: #f00;
  background-color: #fcc;
}

/* 土曜日 */
.calendar th:nth-child(7),
.calendar td:nth-child(7) {
  color: #00f;
  background-color: #ccf;
}

:nth-child擬似クラスを使うと、1番目の子要素、7番目の子要素のように、順番を使った指定が可能となります。

JavaScriptを作成

カレンダーのHTML要素を参照

JavaScriptで中身を生成するのはcaption要素とtbody要素なので、この2つをあらかじめ参照しておきます。

const calendar = document.querySelector('.calendar');
const calendarCaption = calendar.querySelector('caption');
const calendarBody = calendar.querySelector('tbody');

対象の年と月を取得

今回は今月のカレンダーを作成するので、new Date();で現在の時間を取得し、そこから年と月を取り出しておきます。

const now = new Date();
const nowYear = now.getFullYear();
const nowMonth = now.getMonth();

new Date(2018, 5, 1);のように、引数に年月日を指定することで、別な月のカレンダーとすることも可能です。

古いWebサイトや書籍では、年の取得にgetYearを使っていることがありますが、現在では非推奨となっていますので、年の取得には必ずgetFullYearを使うようにしてください。

初日の曜日と、末日の日付を取得

カレンダーを作るにはこの2つの情報が必要となるため、生成したDateオブジェクトを使って、これらを求めておきます。

const firstDayOfMonth = new Date(nowYear, nowMonth, 1).getDay();
const lastDateOfMonth = new Date(nowYear, nowMonth + 1, 0).getDate();

月の末日は「翌月1日の1日前」で求めることができます。Dateオブジェクトはこうした繰り上がりや繰り下がりも内部でうまく処理してくれるので、便利です。

2月は、うるう年であるかどうかによって日数が変わりますが、この方法を使って末日を求める場合は、JavaScript側でうるう年かどうかを判断してくれます。年を求めて4で割って…と計算する手間を省略できるので、ぜひこの方法を覚えておきましょう。

日付に使う数値の配列を用意する

理論上、カレンダーは最大で6行目(第6週)まであるため、最終的に7×6で42個のセルを生成します。月によっては第4~5週で終わりますが、今回はそのような月であっても、とりあえず6行目まで生成してしまいます。

まず、1~42の連番で配列を作ります。続いて、この配列の数字を、初日の曜日に応じて右にシフトさせていきます。1つ前で初日の曜日を求めたのは、このためです。

const dateArray = [
   1,  2,  3,  4,  5,  6,  7,
   8,  9, 10, 11, 12, 13, 14,
  15, 16, 17, 18, 19, 20, 21,
  22, 23, 24, 25, 26, 27, 28,
  29, 30, 31, 32, 33, 34, 35,
  36, 37, 38, 39, 40, 41, 42
].map(function (date) {
  return date - firstDayOfMonth
});

例えば、初日の曜日が水曜日(getday() = 3)の月の場合は、配列内の各数値から3が引かれるため、結果は以下のような配列となります。

// 初日の曜日が水曜日の場合、配列は以下のようになる
[
  -2, -1,  0,  1,  2,  3,  4,
   5,  6,  7,  8,  9, 10, 11,
  12, 13, 14, 15, 16, 17, 18,
  19, 20, 21, 22, 23, 24, 25,
  26, 27, 28, 29, 30, 31, 32, 
  33, 34, 35, 36, 37, 38, 39
]

1が日曜日の位置(左端)から右に3つシフトして、水曜日の位置(左から4番目)になりました。このように、右にシフトしたい数と、getDayで得られる数が一致しているというのがポイントです。

カレンダーにセルを挿入する

いよいよ、カレンダーにセルを挿入していきます。

// 6週間(6行)あるため、6回ループする
for (let i = 0; i < 6; i++) {
  // カレンダーに行を挿入する
  const weekRow = calendarBody.insertRow(-1);
  // 日付の配列から1行分(1週間分)の数字を切り取る
  const dateSubArray = dateArray.slice(i * 7, i * 7 + 7)
  // 切り取った配列をtdタグに変換し、結合して行に挿入する
  weekRow.innerHTML = dateSubArray.map(function (date) {
    // 配列の数字が1より小さいか、月の末日より大きい場合は空白セル
    date = date < 1 || date > lastDateOfMonth ? '' : date;
    return '<td>' + date + '</td>'
  }).join('');
}

insertRowメソッドでは、どこに行を挿入するかを引数で指定しますが、-1を渡すと、末尾に挿入してくれます。

配列から1週間分の数字を切り取り、各数字をセルのタグに変換して文字列に結合、それを行に入れることで、カレンダーにセルが挿入されます。

完成版と動作サンプル

ここまでのソースコードの完成版と動作サンプルは、以下でご確認ください。

See the Pen JavaScriptで今月のカレンダーを生成する方法 by sii (@sii_side) on CodePen.dark

このように、Dateオブジェクトを活用することで、日付や時間の処理を比較的手軽に扱うことができるようになります。