質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.63%

JavaScriptのカレンダーのif文によるエラー

解決済

回答 5

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 799

ntttt

score 18

const weeks = ['日', '月', '火', '水', '木', '金', '土'];
          const date = new Date();
          let year = date.getFullYear();
          let month = date.getMonth();
function showCalendar(year, month) {
            const calendarHtml = createCalendar(year, month);
            const sec = document.createElement("section");
            sec.innerHTML = calendarHtml;
            document.querySelector("#calendar").appendChild(sec);

            month ++;
            if(month > 12) {
              year ++;
              month = 1;
            }
          }
function createCalendar(year, month) {
            let today = date.getDate();
            const startDate = new Date(year, month ,1);
            const endDate = new Date(year, month + 1, 0);
            const endDayCount = endDate.getDate();
            const lastMonthEndDate = new Date(year, month , 0);
            const lastMonthendDayCount = lastMonthEndDate.getDate();
            const startDay = startDate.getDay();
            let dayCount = 1;
            let calendarHtml = "";

            calendarHtml += `<h1>${year}/${month + 1}</h1>`;
            calendarHtml += "<table>";
            calendarHtml += "<tr>"
            for(let i = 0; i < weeks.length; i++) {
              calendarHtml += "<th>" + weeks[i] + "</th>";
            }
            calendarHtml += "</tr>"

**ここからがカレンダーを作成するコードになります**
            for(let w = 0; w < 6; w++) {
              calendarHtml += "<tr>";

              for(let d = 0; d < 7; d++) {
                if(w == 0 && d < startDay) {
          //lastMonthendDayCountは先月の末日の数値
          //startDayは今月の最初の日の曜日の数値
                  let num = lastMonthendDayCount - startDay + d + 1;
                  calendarHtml += `<td class = "is-disabled">${num}</td>`;
                } else if(dayCount > endDayCount) {
          //dayCountは1
          //endDayCountは今月の末日の数値
                  let num = dayCount - endDayCount;
                  calendarHtml += `<td class="is-disabled">${num}</td>`;
                  dayCount ++;
         //todayは今日の数値
                } else if(dayCount < today) {
                  calendarHtml += `<td class="calendar_td" data-date="${year}/${month}/${dayCount}">${dayCount}</td>`;
                  dayCount ++;
                } else if(dayCount == today) {
                  calendarHtml += `<td class="calendar_td today" data-date="${year}/${month}/${dayCount}">${dayCount}</td>`;
                } else if(endDayCount > today) {
                  calendarHtml += `<td class="calendar_td" data-date="${year}/${month}/${dayCount}">${today}</td>`;
                  today ++;
                  console.log(today);
                }
              }

              calendarHtml += "</tr>";
            }
            calendarHtml += "</table>";
            return calendarHtml;
          }
**ここまでがカレンダーを作成するコードになります**

          function moveCalendar(e) {
            document.querySelector("#calendar").innerHTML = "";
            if(e.target.id === 'prev') {
              month --;
              if(month < 1) {
                year --;
                month = 12;
              }
            }

            if(e.target.id === "next") {
              month ++;
              if(month > 12) {
                year ++;
                month = 1;
              }
            }
            showCalendar(year, month);
          }

          document.querySelector("#prev").addEventListener("click", moveCalendar);
          document.querySelector("#next").addEventListener("click", moveCalendar);

JavaScriptを勉強中の者です。
カレンダーで今日の日付の場所にマークアップをしたいのですが、今のコードのままでは今日以降の日付が今日と同じ日付になってしまいます。
日付に関するコードは「ここからがカレンダーを作成するコードになります」以降から「ここまでがカレンダーを作成するコードになります」までとなります。
至らない点があるとは思いますが、お知恵を拝借できたら幸いです。
宜しくお願いします。

イメージ説明

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • yambejp

    2019/06/04 12:16

    とりえあずおかしい挙動でもよいのでコピペで動くソースを提示ください

    キャンセル

  • m.ts10806

    2019/06/04 13:00

    タイトルには要件(起きている問題、実現したいこと)を記載してください。
    タグにある内容や汎用的すぎる内容はあまり好ましくありません

    キャンセル

回答 5

checkベストアンサー

+1

もっとロジックを考え直した方がよい。
appendChild 使えるなら innerHTML を不使用にしては?
変数 w が多すぎるときの問題は?
とにかくごちゃごちゃしすぎ。

              for(let d = 0; d < 7; d++) {
                if(w == 0 && d < startDay) {
          //lastMonthendDayCountは先月の末日の数値
          //startDayは今月の最初の日の曜日の数値
                  let num = lastMonthendDayCount - startDay + d + 1;
                  calendarHtml += `<td class = "is-disabled">${num}</td>`;
                } else if(dayCount > endDayCount) {
          //dayCountは1
          //endDayCountは今月の末日の数値
                  let num = dayCount - endDayCount;
                  calendarHtml += `<td class="is-disabled">${num}</td>`;
                  dayCount ++;
         //todayは今月の末日の数値
                } else if(dayCount < today) {
                  calendarHtml += `<td class="calendar_td" data-date="${year}/${month}/${dayCount}">${dayCount}</td>`;
                  dayCount ++;
                } else if(dayCount == today) {
                  calendarHtml += `<td class="calendar_td today" data-date="${year}/${month}/${dayCount}">${dayCount}</td>`;
                  dayCount ++;
                } else  {
                  calendarHtml += `<td class="calendar_td" data-date="${year}/${month}/${dayCount}">${dayCount}</td>`;
                  dayCount ++;
                  console.log(dayCount);
                }
              }

そのうち万年カレンダーでも書いてみようかなと思っていたので書いてみた。
先月と来月の余計な日付と、今日という存在がロジックを複雑にするね。
もうちょっと熟考する余地があるね。

<html lang="ja">
<meta charset="utf-8">
<title></title>
<style>
td {
  text-align: center;
}
tr td:first-Of-type {
  color: red;
}
tr td:nth-Of-type(7) {
  color: blue;
}
td.is-disabled {
  color: silver !important;
}
td.today {
  background: yellow;
}

</style>
<body>
  <div id="hoge"></div>
  <input type="button" value="prev" id="prev">
  <input type="button" value="next" id="next">
  <hr>
  <div id="fuga"></div>
  <input type="button" value="prev" id="prev2">
  <input type="button" value="next" id="next2">


<script>

{
  const
    WEEK_JP = ['日', '月', '火', '水', '木', '金', '土'],
    DATE_FN = ['getFullYear', 'getMonth', 'getDate', 'getDay'],
    OPTION = {

    };

  function addMonth (dt, n) {
    dt.setMonth (dt.getMonth () + n);
    return dt;
  }

  function getDTValue (dt = new Date) {
    return DATE_FN.map (f => dt[f]());
  }

  function removeChild (e) {
    e.remove ();
  }

  //____________________

  function init () {
    let
      doc = this.parent.ownerDocument,
      tbl = doc.createElement ('table'),
      thd = tbl.createTHead (),
      tr = thd.insertRow ();

    tbl.createCaption ();
    WEEK_JP.forEach (w => tr.insertCell ().textContent = w);
    this.table = this.parent.appendChild (tbl); 
  }

  //____________________

  class Calendar {
    constructor (parent, dateObj = new Date, option = {}) {
      this.parent = parent;
      this.current = dateObj;
      this.option = Object.assign ({}, OPTION, option);
      init.call (this);
      this.show ();
    }

    show () {
      let
        tbodies = [...this.table.tBodies],
        tbody = this.parent.ownerDocument.createElement ('tbody'),
        [ty, tm, td, tw] = getDTValue (this.current),
        [cy, cm, cd, cw] = getDTValue (new Date (ty, tm + 1, 0)),//今月の月末
        [py, pm, pd, pw] = getDTValue (new Date (ty, tm, 0)),//先月の月末
        [ny, nm, nd] = getDTValue (),
        f = (pw + 1) % 7, //1日の曜日
        map = [
          ...Array.from (Array (f), (_, i) => pd - f + i + 1),//先月の日
          ...Array.from (Array (cd), (_, i) => i + 1),//今月の日
          ...Array.from (Array (6 - cw), (_, i) => i + 1)//翌月の日
        ],
        isToday = ny === ty && nm === tm ? nd + f -1: -1;

      tbodies.forEach (removeChild);
      this.table.caption.textContent = [cy, cm + 1].join (' / ');

      for (let cnt = 0, m; map.length; ) {
        m = map.splice (0, 7);
        let tr = tbody.insertRow (-1);
        for (let n of m) {
          let td = tr.insertCell (-1);
          td.textContent = n;
          if (f > cnt || cnt >= (f + cd))
            td.classList.add ('is-disabled');
          else if (cnt == isToday)
            td.classList.add ('today');
          cnt++;
        }
      }

      this.table.appendChild (tbody);
      return this;
    }


    next (n) {
      addMonth (this.current, n);
      return this.show ();
    }

  }

  this.Calendar = Calendar;
}

//_________________________

const calendar = new Calendar (hoge);
calendar.handleEvent = function (event) {
  switch (event.target.id) {
    case 'prev': this.next (-1); break;
    case 'next': this.next (1);  break;
  }
};

document.addEventListener ('click', calendar, false);

//______________________________
//2つ目
const calendar2 = new Calendar (fuga, new Date (2020, 7, 1));
calendar2.handleEvent = function (event) {
  switch (event.target) {
    case prev2: this.next (-1); break;
    case next2: this.next (1);  break;
  }
};

document.addEventListener ('click', calendar2, false);



</script>

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/06/05 10:23

    あいかわらず、モダンでスマートな書き方で素晴らしいです!
    今、ES6〜、猛勉強中なので、どうか参考にさせてください。
    横槍失礼しました。

    キャンセル

  • 2019/06/05 15:54

    お恥ずかしいかぎり・・・。

    キャンセル

  • 2019/06/05 20:59

    とても参考になるカレンダーのコードを教えて頂きありがとうございます。
    私にはまだまだ理解できていないですが、こちらのコードを参考にjsの勉強を進めていきたいと思います。
    本当にありがとうございました。

    キャンセル

0

まずは、コメント内もしくは変数名以外に全角文字を使うのはやめましょう。
一応、全角文字が許可されている言語ですが、不必要な箇所で使うと、思わぬエラーの原因になります。
(一行コメントの前に大量の全角スペースがありました)
そして、コードを書くときは、サンプルの場合でも、記法は正しくした方が、回答しやすいものとなり、よろしいかと。
(JavaScriptでは、**コメント**の形式はコメントアウトになりません)

さて、回答です。
みたところ、原因は、
dayCount < today

endDayCount > today
の条件が通っていないからと思われます。
dayCount++と、today++が実行されてないわけですね。
ifの条件式は、基本的に上から順番に条件を見ていき、マッチする条件以降は参照しません。
現状だと、dayCount == todayで処理がストップし、
endDayCount > todayが通らないので、
today++が実行されず、だからです。
そして、今回のやることとしては、todayはあくまで不動でなければ、そもそもの前提が崩れる条件式となっているため、
正しくカレンダーにはなりません。
よって、下記のような、条件式が正解となるでしょう。

for(let d = 0; d < 7; d++) {
  if(w == 0 && d < startDay) {
    //lastMonthendDayCountは先月の末日の数値
    //startDayは今月の最初の日の曜日の数値
    let num = lastMonthendDayCount - startDay + d + 1;

    calendarHtml += `<td class = "is-disabled">${num}</td>`;
  } else if(dayCount > endDayCount) {
    //dayCountは1
    //endDayCountは今月の末日の数値
    let num = dayCount - endDayCount;

    calendarHtml += `<td class="is-disabled">${num}</td>`;
    dayCount ++;
    //todayは今月の末日の数値
  } else if(dayCount < today) {
    calendarHtml += `<td class="calendar_td" data- 
    date="${year}/${month}/${dayCount}">${dayCount}</td>`;
    dayCount ++;
  } else if(dayCount == today) {
    calendarHtml += `<td class="calendar_td today" data-date="${year}/${month}/${dayCount}">${dayCount}</td>`;
    // ここでも、dayCountをプラスしないと、日付は当然進まない。
    dayCount ++;
  } else if(endDayCount > today) {
    // 下のあくまで、dayCountを表示という考えのもと、文字列表示も、dayCountを使う
    calendarHtml += `<td class="calendar_td" data-date="${year}/${month}/${dayCount}">${dayCount}</td>`;
    // あくまで、プラスするのは、dayCountにする。todayはあくまで、今日としないと、上の条件式の前提が崩れる
    dayCount ++;
  }
}

それと、hai_haiさんがおっしゃる通り、今回原因の特定が困難になったのは、コードの書き方にも原因があるかとおもいますので、簡潔に書くように、必要な処理を整理して書くようにすると、バグも見つけやすいコードになっていくと思います。
(今回私の書いたコードは、質問者さんのまま、変えております。
ただし、月末日が、金曜日であっても、最後の週が追加されてしまっています。
↑今回の質問の要件ではないため、スルーしてます。)

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/06/04 18:22

    ご回答ありがとうございました。
    miyabi_takatsukさんのご説明がとても分かりやすかったので、実行されない原因が理解できました。
    原因だけではなく、jsのルールを教えて頂きありがとうございました。

    キャンセル

  • 2019/06/04 22:48 編集

    もし解決したのであれば、ベストアンサーを選出して、質問を閉じましょう。
    あと、質問修正依頼も、ご覧いただき、質問文を修正しましょう。
    次質問される時に活きてくるはずですので。また、この質問を他の、同じことで悩んでいる誰かの解決の糸口にもなるかもしれませんので、解決後でも、質問修正は大事かと思います。

    キャンセル

  • 2019/06/05 20:46

    質問修正依頼を見落としてました。
    かしこまりました。質問修正して、ベストアンサーを決めて質問を終了させていただきます。
    色々と教えて頂きありがとうございました。

    キャンセル

0

祝日に対応してみました。

長くなったので分割します。

<!DOCTYPE html>
<html lang="ja">
<meta charset="utf-8">
<title></title>
<style>
td {
  text-align: center;
}
tr td:first-Of-type {
  color: red;
}
tr td:nth-Of-type(7) {
  color: blue;
}
td.disabled {
  color: silver !important;
}
td.today {
  border-bottom: 2px solid green;
  background: rgba(255,255,0,.3);
}
td.holiday {
  background: rgba(255,0,0,.1);
  color: red;
}

</style>
<body>
  <div id="hoge"></div>
  <input type="button" value="prev" id="prev">
  <input type="button" value="next" id="next">

<script>

{
  const
    CURRENT_DATE = new Date,
    CURRENT_YEAR = CURRENT_DATE.getFullYear (),
    TITLE_FURIKAE = '(振替休日)',
    TITLE_KOKUMIN = '(国民の休日)',

    SHUKUJITU_FUNC = [
      // 国民の祝日 「祝日法」 1948-7-20施行
      ganjitu, // 元日
      seijin_no_hi, // 成人の日
      kenkokukinen_no_hi, // 建国記念の日
      shunbun_no_hi, // 春分の日
      shouwa_tennou, // 昭和の日、みどりの日、昭和天皇誕生日
      kenpou_kinenbi, // 憲法記念日
      midori_no_hi, // みどりの日
      kodomo_no_hi, // こどもの日
      umi_no_hi, // 海の日
      yama_no_hi, // 山の日
      keirou_no_hi, // 敬老の日
      shuubun_no_hi, // 秋分の日
      taiiku_no_hi, // 体育の日
      bunka_no_hi, // 文化の日
      kinroukansha_no_hi, // 勤労感謝の日
      heisei_tennou, //(平成)天皇誕生日

      // 祝祭日     「年中祭日祝日ノ休暇日ヲ定ム」 1873-10-14施行
      sihousetu, //四方節 -    
      sinnenenkai, //新年宴会
      kigensetu, //紀元節
      tentyousetu, //天長節
      tentyousetu_shukujitu, //天長節祝日
      meijisetu, //明治節

      gensisai, //元始祭
      koumeitennousai, //孝明天皇祭
      shunkikoureisai, //春季皇霊祭
      jinmutennousai, //神武天皇祭
      meijitennousai, //明治天皇祭
      kannamesai, //神嘗祭
      shuukikoureisai, //秋季皇霊祭
      kannamesai2, //神嘗祭
      niinamesai, //新嘗祭
      taishoutennousai //大正天皇祭
    ];

  //_________________________________________________________________

  //指定の年月のn週のw曜日の日にちを返す
  function getWN (year, month, week_num, day_num) {
    let
      d = new Date (year, month, 1),
      td = day_num - d.getDay () + 1;
    if (td <= 0)
      td += 7;
    td += 7 * (week_num - 1);

    return td;
  }

  //日付順にソート用
  function sortByDate (a, b) {
    return a.date > b.date;
  }

  //次の日にする
  function nextDate (d = new Date, n = 1) {
    d.setDate (d.getDate () + n);
    return d;
  }

  //日付が等しいか
  function isSameDate (a, b) {
    let rst =
      (!a) || (!b) ||
      (a.getFullYear () !== b.getFullYear ()) ||
      (a.getMonth ()    !== b.getMonth ()) ||
      (a.getDate ()     !== b.getDate ());
    return !rst;
  }

  //年月日の属性を付加する
  function addYMDmethod (list) {
    for (let rec of list) {
      let d = rec.date;
      rec.year = d.getFullYear ();
      rec.month = d.getMonth () + 1;
      rec.day = d.getDate ();
    }
    return list;
  }

  function ymd (dt = new Date) {
    return dt ? ['getFullYear', 'getMonth', 'getDate'].map (fn => dt[fn]()).join ('-'): null;
  }


  //_________________________________________________________________

  //元日
  function ganjitu (y) {
    return 1948 < y ? {name: '元日', date: new Date (y, 0, 1)}: null;
  }
  //成人の日
  function seijin_no_hi (y) {
   return 1948 < y ? {name: '成人の日', date: new Date (y, 0, y < 2000 ? 15: getWN (y, 0, 2, 1))}: null;
  }
  //建国記念の日
  function kenkokukinen_no_hi (y) {
    return 1948 < y ? { name: '建国記念の日', date: new Date (y, 1, 11)}: null;
  }
  //春分の日
  function shunbun_no_hi (y) {
    if (y <= 1948) return null;
    let d;

    if (y < 1980)
      d = parseInt(20.8357 + 0.242194 * ( y - 1980), 10) - parseInt((y - 1983) / 4, 10);
    else if (y < 2100)
      d = parseInt(20.8431 + 0.242194 * ( y - 1980), 10) - parseInt((y - 1980) / 4, 10);
    else if (y < 2150)
      d = parseInt(20.8510 + 0.242194 * ( y - 1980), 10) - parseInt((y - 1980) / 4, 10);
    else
      throw new Error ('範囲外です' + y);

    return { name: '春分の日', date: new Date (y, 2, d) };
  }
  //天皇誕生日, みどりの日, 昭和の日
  function shouwa_tennou (y) {
    return 1948 < y ? {name: y < 1989 ? '天皇誕生日': y < 2007 ? 'みどりの日': '昭和の日', date: new Date (y, 3, 29)}: null;
  }
  //憲法記念日
  function kenpou_kinenbi (y) {
    return 1948 < y ? { name: '憲法記念日', date: new Date (y, 4, 3)}: null;
  }
  //みどりの日
  function midori_no_hi (y) {
    return 2006 < y ? { name: 'みどりの日', date: new Date (y, 4, 4)}: null;
  }
  //こどもの日
  function kodomo_no_hi (y) {
    return 1949 < y ? { name: 'こどもの日', date: new Date (y, 4, 5)}: null;
  }
  //海の日
  function umi_no_hi (y) {
    return 1995 < y ? { name: '海の日', date: new Date (y, 6, 2002 < y ? getWN (y, 6, 3, 1): 20 )}: null;
  }
  //山の日
  function yama_no_hi (y) {
    return 2015 < y ? {name: '山の日', date: new Date (y, 7, 11)}: null;
  }
  //敬老の日
  function keirou_no_hi (y) {
    return 1965 < y ? {name: '敬老の日', date: new Date (y, 8, y < 2003 ? 15: getWN (y, 8, 3, 1))}: null;
  }
  //秋分の日
  function shuubun_no_hi (y) {
    if (y < 1948) return null; //法の施行後

    let d;
    if (y < 1980)
      d = parseInt(23.2588 + 0.242194 * (y - 1980), 10) - parseInt((y - 1983) / 4, 10);
    else if (y < 2100)
      d = parseInt(23.2488 + 0.242194 * (y - 1980), 10) - parseInt((y - 1980) / 4, 10);
    else if (y < 2150)
      d = parseInt(24.2488 + 0.242194 * (y - 1980), 10) - parseInt((y - 1980) / 4, 10);
    else
      throw new Error ('範囲外です');

    return { name: '秋分の日', date: new Date (y, 8, d)};
  }
  //体育の日
  function taiiku_no_hi (y) {
    return 1965 < y ? {name: '体育の日', date: new Date (y, 9, y < 2000 ? 10: getWN (y, 9, 2, 1))}: null;
  }
  //文化の日
  function bunka_no_hi (y) {
    return 1947 < y ? {name: '文化の日', date:  new Date (y, 10, 3)}: null;
  }
  //勤労感謝の日
  function kinroukansha_no_hi (y) {
    return 1947 < y ? {name: '勤労感謝の日', date:new Date (y, 10, 23)}: null;
  }
  //天皇誕生日
  function heisei_tennou (y) {
    return 1988 < y ? y < 2019 ? { name: '天皇誕生日', date: new Date (y, 11, 23)}: null: null;
  }
  //振替休日
  function furikaeKyuujitu (list = [ ]) {
    let
      furikae = [ ],
      prev = null;
      begin = +new Date (1973, 3, 12), //.getTime ();
      end   = +new Date (2007, 0, 1); //.getTime () --> 2006/12/31:23:59:59:999?

    list.forEach (obj => {
      if (+obj.date < begin) return;//1973以前は振替休日がない

      let date = new Date (obj.date);

      //2006/12/31以前:国民の祝日が日曜のとき次の日は振替休日
      if (+date < end) {
        if (0 === date.getDay ())//日曜
          furikae.push ({name: TITLE_FURIKAE, date: nextDate (date)});
      }
      //2007以降、国民の祝日が連続しており、その中に日曜が含まれるとき次の平日は振替休日
      else {
        if (prev) {
          if (isSameDate (prev, date))
            nextDate (prev);
          else {
            furikae.push ({name: TITLE_FURIKAE, date: prev});
            prev = null;
          }
        }
        if (0 === date.getDay ())
          prev = nextDate (date);
      }  
    });

    return furikae;
  }

  //国民の休日
  function kokuminKyuujitu (list = [ ]) {
    if (! list.length)
      throw new Error ('');

    let
      kyuujitu = [ ],
      y = list[0].date.getFullYear ();//祝日の配列の最初のDATEを基準とする
      prv = null,
      begin    = new Date (1985, 11, 27);

    //1986-2006の5月4日の特殊処理
    if (1986 <= y && y <= 2006)
      kyuujitu.push ({ name: TITLE_KOKUMIN, date: new Date (y, 4, 4)});

    //1985/12/27以降
    for (let cur of list) {
      let date = new Date (cur.date);
      if (begin <= +date) {
        if (isSameDate (prv, date)) {
          kyuujitu.push ({name: TITLE_KOKUMIN, date: nextDate (prv, -1)});
        }
        prv = nextDate (date, 2);
      }
    }
    return kyuujitu;
  }

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/06/05 15:52

    ごめんなさい。作ってたら長くなって分割投稿になりました。
    って、文字制限があったのかよ~!1万文字なんて少なすぎだろう?
    見直せよ!
    祝日は、正しい結果を返すのか検証していません。

    キャンセル

0

  //_________________________________________________________________

  // 国民の祝日 「祝日法」 1948-7-20施行
  //四方節
  function sihousetu (y) {//法令で定められてはいない
    return 1873 < y ? y <= 1948 ? { name: '四方節', date: new Date (y, 0, 1) }: null: null;
  }
  //新年宴会
  function sinnenenkai (y) {
    return 1873 < y ? { name: '新年宴会', date: new Date (y, 0, 5) }: null;
  }
  //紀元節
  function kigensetu (y) {
    return 1873 < y ? { name: '紀元節', date: new Date (y, 1, 11) }: null;
  }
  //天長節
  function tentyousetu (y) {
    let date;
    switch (true) {
    case y < 1874 : case y === 1912 : case 1948 < y : return null; break;
    case y < 1912 : date = new Date (y, 10, 3); break;
    case y < 1927 : date = new Date (y, 7, 31); break;
    case y < 1949 : date = new Date (y, 3, 29); break;
    default : throw new Error ('year = ' + y); break;
    }

    return { name: '天長節', date };
  }
  //天長節祝日
  function tentyousetu_shukujitu (y) {
    return 1913 <= y ? y <= 1926 ? { name: '天長節祝日', date: new Date (y, 9, 31) }: null: null;
  }
  //明治節
  function meijisetu (y) {
    return 1927 <= y ? y < 1948 ? { name: '明治節', date: new Date (y, 10, 3) }: null: null;
  }

  //元始祭
  function gensisai (y) {
    return 1873 < y ? y <= 1948 ? { name: '元始祭', date: new Date (y, 0, 3) }: null: null;
  }
  //孝明天皇祭
  function koumeitennousai (y) {
    return 1873 < y ? y <= 1912 ? { name: '孝明天皇祭', date: new Date (y, 0, 30) }: null: null;
  }
  //春季皇霊祭
  function shunkikoureisai (y) {
    return 1879 <= y ? y <= 1948 ? { name: '春季皇霊祭', date: new Date (y, 2, 21) }: null: null;
  }
  //神武天皇祭
  function jinmutennousai (y) {
    return 1873 < y ? y <= 1948 ? { name: '神武天皇祭', date: new Date (y, 3, 3) }: null: null;
  }
  //明治天皇祭
  function meijitennousai (y) {
    return 1913 <= y ? y <= 1926 ? { name: '明治天皇祭', date: new Date (y, 6, 30) }: null: null;
  }
  //神嘗祭
  function kannamesai (y) {
    return 1873 <= y ? y <= 1878 ? { name: '神嘗祭', date: new Date (y, 8, 17) }: null: null;
  }
  //秋季皇霊祭
  function shuukikoureisai (y) {
    return 1878 <= y ? y < 1948 ? { name: '秋季皇霊祭', date: new Date (y, 8, 23) }: null: null;
  }
  //神嘗祭(2)
  function kannamesai2 (y) {
    return 1879 <= y ? y < 1948 ? { name: '神嘗祭', date: new Date (y, 9, 17) }: null: null;
  }
  //新嘗祭
  function niinamesai (y) {
    return 1873 <= y ? y < 1948 ? { name: '新嘗祭', date: new Date (y, 10, 23) }: null: null;
  }
  //大正天皇祭
  function taishoutennousai (y) {
    return 1927 <= y ? y < 1948 ? { name: '大正天皇祭', date: new Date (y, 11, 25) }: null: null;
  } 


  //_________________________________________________________________

  //皇室慶弔行事
  function kousitu_gyouji (y) {
    switch (y) {
      case 1915 :
        return [
          {name: '即位の礼',  date: new Date (y, 10, 10)},
          {name: '大嘗祭',    date: new Date (y, 10, 14)},
          {name: '大饗第1日', date: new Date (y, 10, 16)}
        ];
        break;

      case 1928 :
        return [
          {name: '即位の礼',  date: new Date (y, 10, 10)},
          {name: '大嘗祭',    date: new Date (y, 10, 14)},
          {name: '大饗第1日', date: new Date (y, 10, 16)}
        ];
        break;

    case 1959 :
      return [{name: '皇太子・明仁親王の結婚の儀', date: new Date (y, 3, 10)}];
      break;

    case 1989 :
      return [{name: '昭和天皇の大喪の礼', date: new Date (y, 1, 24)}];
      break;

    case 1990 :
      return [{name: '即位の礼正殿の儀', date: new Date (y, 10, 12)}];
      break;

    case 1993 :
      return [{name: '皇太子・皇太子徳仁親王の結婚の儀', date: new Date (y, 5, 9)}];
      break;

    case 2019 :
      return [
        {name: '天皇の即位', date: new Date (y, 4, 1)},
        {name: '即位の礼正殿の儀', date: new Date (y, 9, 22)}
      ];
      break;

    default :
      return [ ];
    }
  }


  //_________________________________________________________________

   class Shukujitu {
    constructor (year = CURRENT_YEAR) {
      this.year = year;
      this.holidays = Shukujitu.getHolidayList (year);
    }


  //_____
    // arg0 = DateObject or Year(integer);
    //arg1 = 0~11は月数、省略or -1 は、指定年のすべての祝日を返す
    static getHolidayList (date = CURRENT_DATE, month = -1) {
      if (! date instanceof Date) {
        if (Number.isInteger (date))
          date = new Date (date, 0, 1);
        else
          throw new Error ('年数の値が範囲外');
      }
      if (month < -1 || 12 < month)
        throw new Error ('月数の値が範囲外');

      let
        year = typeof date === 'object' ? date.getFullYear (): date,
        holidays = [ ], furikae = [ ], kokumin = [ ], kousitu = [ ], shukujitu = [ ];

      SHUKUJITU_FUNC.forEach (func => {
        let rst = func (year);
        if (rst)
          holidays.push (rst);
      });

      holidays = holidays.sort (sortByDate);
      kousitu  = kousitu_gyouji (year);//皇室行事は祝日と重ならないのでこのまま混合する
      furikae  = furikaeKyuujitu (holidays);
      shukujitu = holidays.concat (kousitu).sort (sortByDate);
      kokumin  = kokuminKyuujitu (shukujitu);

      holidays = addYMDmethod (shukujitu.concat (furikae, kokumin).sort (sortByDate));
      if (-1 < month)
        holidays = holidays.filter (dt => month === dt.date.getMonth ());

        return holidays;
    }
  }

  //_____

  this.Shukujitu = Shukujitu;
}


//________________________________________________________

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/06/05 15:52

    これが2

    キャンセル

0

{
  const
    WEEK_JP = ['日', '月', '火', '水', '木', '金', '土'],
    WEEK_EN = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
    DATE_FN = ['getFullYear', 'getMonth', 'getDate', 'getDay'];

  function addMonth (dt, n) {
    dt.setMonth (dt.getMonth () + n);
  }

  function addDay (dt, n) {
    dt.setDate (dt.getDate () + n);
  }

  function isSameDate (a, b) {
    return DATE_FN.every (f => a[f]() === b[f]());
  }

  function getDTValue (dt = new Date) {
    return DATE_FN.map (f => dt[f]());
  }

  //____________________

  function init (e) {
    let
      doc = e.ownerDocument,
      tbl = doc.createElement ('table'),
      cap = tbl.createCaption (),
      thd = tbl.createTHead (),
      tr  = thd.insertRow ();

    WEEK_JP.forEach (w => tr.insertCell ().textContent = w);
    return e.appendChild (tbl); 
  }

  //____________________

  class Calendar {

    constructor (parent, dt = new Date) {
      if (1 > arguments.length)
        throw new Error ('引数が不足');

      this.table = init (parent);
      this.parent = parent;
      this.current = dt;
      this.show ();
    }


    show () {
      let
        tbodies = this.table.tBodies,
        tbody = this.parent.ownerDocument.createElement ('tbody'),
        today = new Date,//今日
        [Y, M] = getDTValue (this.current),//Classが持つ基準のDATE
        current = new Date (Y, M + 1, 0),//月末
        [cy, cm, cd, cw] = getDTValue (current),//月末の詳細
        n0 = (7 + cw - cd % 7) % 7 + cd,//カレンダーに描く最初の日までの日数を求める
        n1 = n0 + 7 - cw,//カレンダーに表示する日数を求める
        holiday = new Map (Shukujitu.getHolidayList (Y, M).map (dt=> [dt.date.getDate (), dt]) || []),
        tr, td;

      Array.from (tbodies, e => e.remove ());//tbody 要素群をいったん削除
      this.table.caption.textContent = [Y, M + 1].join (' / ');//caption要素に代入

      addDay (current, -n0);//基準を最初の日にする
      for (let i = 0; i < n1; i++) {
        let
          [, m, d, w] = getDTValue (current),
          cname = [WEEK_EN[w]];//className

        if (! w)
          tr = tbody.insertRow (-1);//日曜なら行を作る

        td = tr.insertCell (-1);

        if (isSameDate (today, current))
          cname.push ('today');
        if (M != m)
          cname.push ('disabled');
        else if (holiday.has (d)) {
          cname.push ('holiday');
          td.title = holiday.get (d).name;
        }

        td.classList.add (...cname);
        td.textContent = d;
        td.dataset.date = [Y, M + 1, d].join ('-');

        addDay (current, 1);//inc
      }

      this.table.appendChild (tbody);
      return this;
    }


    next (n) {
      addMonth (this.current, n);
      return this.show ();
    }

  }

  this.Calendar = Calendar;
}

//_________________________

const calendar = new Calendar (hoge);
calendar.handleEvent = function (event) {
  switch (event.target.id) {
    case 'prev': this.next (-1); break;
    case 'next': this.next (1);  break;
  }
};

document.addEventListener ('click', calendar, false);

</script>

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/06/05 15:53

    これが3

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.63%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る