/***************************************************************

    SYSTEM   : studio yap

    TITLE    : yap カレンダーの表示

    SCRIPT   : calendar.js

    VERSION  : Ver1.1.5

    LANGUAGE : JavaScript1.3

    CODESET  : UTF-8

    EXPLAIN  : 休業日を明示した営業カレンダーを表示します。

    AUTHOR   : yap

    CREATED  : 2006/11/09 as Ver1.0.1

    UPDATED  : 2008/11/24 as Ver1.1.5

***************************************************************/



//デフォルト値の設定

if (holidays == undefined) {var holidays = '';}  //特別休業日

if (flgHol   == undefined) {var flgHol   = 1;}   //祝日を休みとするフラグ

if (arrReg   == undefined) {var arrReg   = new Array(  //定休日

    new Array(1, 1, 1, 1, 1),  //日曜(第1週,第2週,第3週,第4週,第5週)

    new Array(0, 0, 0, 0, 0),  //月曜(　〃　)

    new Array(0, 0, 0, 0, 0),  //火曜(　〃　)

    new Array(0, 0, 0, 0, 0),  //水曜(　〃　)

    new Array(0, 0, 0, 0, 0),  //木曜(　〃　)

    new Array(0, 0, 0, 0, 0),  //金曜(　〃　)

    new Array(1, 1, 1, 1, 1)); //土曜(　〃　)

}

if (numCal   == undefined) {var numCal   = 1;}   //表示するカレンダー数

if (numCol   == undefined) {var numCol   = 0;}   //１行に表示するカレンダー数

if (offset   == undefined) {var offset   = 0;}   //表示開始年月オフセット

if (styleCur == undefined) {var styleCur = 'color:#009900; font-weight:bold;';}  //今日

if (styleHol == undefined) {var styleHol = 'background-color:#FFCCCC;';}  //休業日

if (styleOpn == undefined) {var styleOpn = 'background-color:#FFFFFF;';}  //営業日

if (styleInv == undefined) {var styleInv = 'background-color:#ECECEC;';}  //無効日

if (styleFes == undefined) {var styleFes = 'color:#FF00FF;';}  //祝日

if (styleSun == undefined) {var styleSun = 'color:#FF0000;';}  //日曜

if (styleSat == undefined) {var styleSat = 'color:#0000FF;';}  //土曜

if (styleWee == undefined) {var styleWee = 'color:#000000;';}  //平日

if (styleDay == undefined) {var styleDay = 'font-size:9pt; border:solid 1px #CCCCCC;';}  //日付部

if (styleCap == undefined) {var styleCap = 'font-size:9pt; border:solid 1px #CCCCCC; background-color:#E0E0FF;';}  //見出し(曜日)

if (styleBtn == undefined) {var styleBtn = 'color:#FFFFFF; font-size:9pt; background-color:#993300;';}  //タイトル(<>ボタン)

if (styleTtl == undefined) {var styleTtl = 'color:#FFFFFF; font-size:9pt; background-color:#993300;';}  //タイトル(年月)

if (styleTbl == undefined) {var styleTbl = 'width:190px; border:solid 1px #666666; border-collapse:collapse;';}  //カレンダー

if (styleDiv == undefined) {var styleDiv = 'float:left; padding:4px;';}  //枠

if (arrWeek  == undefined) {var arrWeek  = new Array('日', '月', '火', '水', '木', '金', '土');}  //曜日名

if (formTtl  == undefined) {var formTtl  = '%Y年%m月';}  //年月フォーマット

if (idCal    == undefined) {var idCal    = 'calendar';}  //カレンダーを表示する位置(ID名)



/***************************************************************

    CAPTION  : 営業カレンダー表示関数

    FUNCTION : calendar

    IN       : curDate=表示開始年月(年/月)(空の時:今月)

    OUT      : なし

    RETURN   : なし

    EXPLAIN  : 休業日を表す営業カレンダーを表示します。

***************************************************************/

function calendar()

{

    //カレンダー数の調整

    if (numCal < 1)  {numCal = 1;}

    if (numCal > 36) {numCal = 36;}



    //休日の設定

    var arrHol = new Array();

    if (holidays) {

        var arrTemp = new Array();

        arrTemp = holidays.split(',');

        for (i = 0; i < arrTemp.length; i++) {

            ret = arrTemp[i].match(/^\s*(-?)\s*(\d{1,2})\s*\/\s*(\d{1,2})\s*$/g);

            if (ret) {

                key = eval(RegExp.$2) + '/' + eval(RegExp.$3);

                arrHol[key] = (RegExp.$1 == '-')? 2: 1;

            }

        }

    }



    //カレンダーの作成

    var strHTML = '';

    for (var mm = 0; mm < numCal; mm++) {



        //初期設定

        var arrMonth = new Array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31); //月テーブル定義

        var myDate = new Date();              //今日の日付を取得

        var curToday = myDate.getDate();      //今日を取得

        var curMonth = myDate.getMonth();     //今月を取得(0～11)

        var curYear  = myDate.getFullYear();  //今年を取得

        myDate.setDate(1);                    //日付を１日に変更

        myDate.setMonth(myDate.getMonth() + offset + mm);  //表示月の設定

        var myYear = myDate.getFullYear();    //西暦年を取得

        if (myYear < 1900) {myYear += 1900;}  //西暦の調整

        if (((myYear % 4) == 0 && (myYear % 100) != 0) || (myYear % 400) == 0) {arrMonth[1] = 29;}  //うるう年の調整

        var myMonth = myDate.getMonth();      //月を取得(0～11)

        var myWeek = myDate.getDay();         //１日の曜日を取得

        var myLine = Math.ceil((myWeek + arrMonth[myMonth]) / 7);  //カレンダーの行数

        var arrCal = new Array(myLine * 7);   //表のセル数分定義



        //カレンダーの計算

        for (var i = 0; i < myLine * 7; i++) {arrCal[i] = '　';}  //カレンダーの初期化

        for (var i = 0; i < arrMonth[myMonth]; i++) {arrCal[i + myWeek] = i + 1;}  //日付の設定



        //カレンダーヘッダの表示

        strHTML += '<div style="' + styleDiv + '">';

        strHTML += '<table cellspacing="0" cellspacing="0" style="' + styleTbl + '">';

        strHTML += '<tr><td title="前月" style="text-align:center; cursor:hand; ' + styleBtn + '" onclick="chgMonth(-1);">&lt;</td>';

        strHTML += '<td colspan="5" style="text-align:center; ' + styleTtl + '">';

        strHTML += formTtl.replace('%Y', myYear).replace('%m', myMonth + 1) + '</td>';

        strHTML += '<td title="翌月" style="text-align:center; cursor:hand; ' + styleBtn + '" onclick="chgMonth(1);">&gt;</td></tr>';



        //カレンダー見出しの表示

        strHTML += '<tr>';

        for (var i = 0; i < 7; i++) {

            strHTML += '<td style="text-align:center; ' + styleCap;

            if (i == 0)      {strHTML += styleSun;}  //日曜スタイルの設定

            else if (i == 6) {strHTML += styleSat;}  //土曜スタイルの設定

            else             {strHTML += styleWee;}  //平日スタイルの設定

            strHTML += '">' + arrWeek[i] + '</td>';

        }

        strHTML += '</tr>';



        //カレンダー日付の表示

        for (var i = 0; i < myLine; i++) {

            strHTML += '<tr>';

            for (var j = 0; j < 7; j++) {

                var myDay = arrCal[(i * 7) + j];

                var myNum = parseInt((myDay - 1) / 7);

                var myStrDate = myYear + '/' + (myMonth + 1) + '/' + myDay;

                var strHolName = ktHolidayName(myStrDate);

                if (strHolName) {

                    var strTitleTag = ' title="' + strHolName + '"';

                } else {var strTitleTag = '';}

                strHTML += '<td' + strTitleTag + ' style="text-align:center; ' + styleDay + ' ';

                if (strHolName)  {strHTML += styleFes;}  //祝日スタイルの設定

                else if (j == 0) {strHTML += styleSun;}  //日曜スタイルの設定

                else if (j == 6) {strHTML += styleSat;}  //土曜スタイルの設定

                else             {strHTML += styleWee;}  //平日スタイルの設定

                if (myDay != '　') {

                    var myStrMD = (myMonth + 1) + '/' + myDay;

                    if (arrHol[myStrMD] == 1)      {strHTML += styleHol;}  //休業日スタイルの設定

                    else if (arrHol[myStrMD] == 2) {strHTML += styleOpn;}  //営業日スタイルの設定

                    else if (strHolName && flgHol) {strHTML += styleHol;}  //祝日スタイルの設定

                    else if (arrReg[j][myNum])     {strHTML += styleHol;}  //定休日スタイルの設定

                    else                           {strHTML += styleOpn;}  //通常日スタイルの設定

                } else                             {strHTML += styleInv;}  //無効日スタイルの設定

                if (myYear == curYear && myMonth == curMonth && myDay == curToday)

                    {strHTML += styleCur;}  //今日スタイルの設定

                strHTML += '">' + myDay + '</td>';

            }

            strHTML += '</tr>';

        }

        strHTML += '</table></div>';

        if ((mm + 1) % numCol == 0) {strHTML += '<br style="clear:both;" />';}

    }

    if (mm % numCol != 0) {strHTML += '<br style="clear:both;" />';}



    //HTMLの書き換え

    document.getElementById(idCal).innerHTML = strHTML;

}



/***************************************************************

    CAPTION  : カレンダー年月変更関数

    FUNCTION : chgMonth

    IN       : num=今月と表示開始年月との差(空の時:今月)

    OUT      : なし

    RETURN   : なし

    EXPLAIN  : 過去または未来の営業カレンダーを表示します。

***************************************************************/

function chgMonth(num)

{

    offset += num;

    calendar();

}



/***************************************************************

    祝日の計算

    CopyRight(C) K.Tsunoda(AddinBox) 2001 All Rights Reserved.

    ( http://www.h3.dion.ne.jp/~sakatsu/index.htm )



    この祝日判定コードは『Excel:kt関数アドイン』で使用している

    ＶＢＡマクロを[JavaScript]に移植したものです。

    この関数では、２００７年施行の改正祝日法(昭和の日)までを

    サポートしています(９月の国民の休日を含む)。



    (*1)このコードを引用するに当たっては、必ずこのコメントも

    一緒に引用する事とします。

    (*2)他サイト上で本マクロを直接引用する事は、ご遠慮願います。

    【 http://www.h3.dion.ne.jp/~sakatsu/holiday_logic.htm 】

    へのリンクによる紹介で対応して下さい。

    (*3)[ktHolidayName]という関数名そのものは、各自の環境に

    おける命名規則に沿って変更しても構いません。

***************************************************************/

// 2008/10/29 変数のvar指定が無く、広域変数扱いになっていたのを修正しました。



var MONDAY = 1;

var TUESDAY = 2;

var WEDNESDAY = 3;



// JavaScriptで扱える日付は1970/1/1～のみ

//var cstImplementTheLawOfHoliday = new Date("1948/7/20");  // 祝日法施行

//var cstAkihitoKekkon = new Date("1959/4/10");             // 明仁親王の結婚の儀

var cstShowaTaiso = new Date("1989/2/24");                  // 昭和天皇大喪の礼

var cstNorihitoKekkon = new Date("1993/6/9");               // 徳仁親王の結婚の儀

var cstSokuireiseiden = new Date("1990/11/12");             // 即位礼正殿の儀

var cstImplementHoliday = new Date("1973/4/12");            // 振替休日施行



// [prmDate]には "yyyy/m/d"形式の日付文字列を渡す

function ktHolidayName(prmDate)

{

  var MyDate = new Date(prmDate);

  var HolidayName = prvHolidayChk(MyDate);

  var YesterDay;

  var HolidayName_ret;



  if (HolidayName == "") {

      if (MyDate.getDay() == MONDAY) {

          // 月曜以外は振替休日判定不要

          // 5/6(火,水)の判定はprvHolidayChkで処理済

          // 5/6(月)はここで判定する

          if (MyDate.getTime() >= cstImplementHoliday.getTime()) {

              YesterDay = new Date(MyDate.getFullYear(),

                                     MyDate.getMonth(),(MyDate.getDate()-1));

              HolidayName = prvHolidayChk(YesterDay);

              if (HolidayName != "") {

                  HolidayName_ret = "振替休日";

              } else {

                  HolidayName_ret = "";

              }

          } else {

              HolidayName_ret = "";

          }

      } else {

          HolidayName_ret = "";

      }

  } else {

      HolidayName_ret = HolidayName;

  }



  return HolidayName_ret;

}



//===============================================================



function prvHolidayChk(MyDate)

{

  var MyYear = MyDate.getFullYear();

  var MyMonth = MyDate.getMonth() + 1;    // MyMonth:1～12

  var MyDay = MyDate.getDate();

  var Result = "";

  var NumberOfWeek;

  var MyAutumnEquinox;



// JavaScriptで扱える日付は1970/1/1～のみで祝日法施行後なので下記は不要

// if (MyDate.getTime() < cstImplementTheLawOfHoliday.getTime()) {

// 　　return ""; // 祝日法施行(1948/7/20)以前

// } else;



  switch (MyMonth) {

// １月 //

  case 1:

      if (MyDay == 1) {

          Result = "元日";

      } else {

          if (MyYear >= 2000) {

              NumberOfWeek = Math.floor((MyDay - 1) / 7) + 1;

              if ((NumberOfWeek == 2) && (MyDate.getDay() == MONDAY)) {

                  Result = "成人の日";

              } else;

          } else {

              if (MyDay == 15) {

                  Result = "成人の日";

              } else;

          }

      }

      break;

// ２月 //

  case 2:

      if (MyDay == 11) {

          if (MyYear >= 1967) {

              Result = "建国記念の日";

          } else;

      } else {

          if (MyDate.getTime() == cstShowaTaiso.getTime()) {

              Result = "昭和天皇の大喪の礼";

          } else;

      }

      break;

// ３月 //

  case 3:

      if (MyDay == prvDayOfSpringEquinox(MyYear)) {  // 1948～2150以外は[99]

          Result = "春分の日";                       // が返るので､必ず≠になる

      } else;

      break;

// ４月 //

  case 4:

      if (MyDay == 29) {

          if (MyYear >= 2007) {

              Result = "昭和の日";

          } else {

              if (MyYear >= 1989) {

                  Result = "みどりの日";

              } else {

                Result = "天皇誕生日";

              }

          }

      } else {

          // JavaScriptで扱える日付は1970/1/1～のみなので下記は不要

          // if (MyDate.getTime() == cstAkihitoKekkon.getTime()) {

          // 　　Result = "皇太子明仁親王の結婚の儀";　　// (=1959/4/10)

          // } else;

      }

      break;

// ５月 //

  case 5:

      switch ( MyDay ) {

        case 3:  // ５月３日

          Result = "憲法記念日";

          break;

        case 4:  // ５月４日

          if (MyYear >= 2007) {

              Result = "みどりの日";

          } else {

              if (MyYear >= 1986) {

                  if (MyDate.getDay() > MONDAY) {

                  // 5/4が日曜日は『只の日曜』､月曜日は『憲法記念日の振替休日』(～2006年)

                      Result = "国民の休日";

                  } else;

              } else;

          }

          break;

        case 5:  // ５月５日

          Result = "こどもの日";

          break;

        case 6:  // ５月６日

          if (MyYear >= 2007) {

              if ((MyDate.getDay() == TUESDAY) || (MyDate.getDay() == WEDNESDAY)) {

                  Result = "振替休日";    // [5/3,5/4が日曜]ケースのみ、ここで判定

              } else;

          } else;

          break;

      }

      break;

// ６月 //

  case 6:

      if (MyDate.getTime() == cstNorihitoKekkon.getTime()) {

          Result = "皇太子徳仁親王の結婚の儀";

      } else;

      break;

// ７月 //

  case 7:

      if (MyYear >= 2003) {

          NumberOfWeek = Math.floor((MyDay - 1) / 7) + 1;

          if ((NumberOfWeek == 3) && (MyDate.getDay() == MONDAY)) {

              Result = "海の日";

          } else;

      } else {

          if (MyYear >= 1996) {

              if (MyDay == 20) {

                  Result = "海の日";

              } else;

          } else;

      }

      break;

// ９月 //

  case 9:

      //第３月曜日(15～21)と秋分日(22～24)が重なる事はない

      MyAutumnEquinox = prvDayOfAutumnEquinox(MyYear);

      if (MyDay == MyAutumnEquinox) {    // 1948～2150以外は[99]

          Result = "秋分の日";           // が返るので､必ず≠になる

      } else {

          if (MyYear >= 2003) {

              NumberOfWeek = Math.floor((MyDay - 1) / 7) + 1;

              if ((NumberOfWeek == 3) && (MyDate.getDay() == MONDAY)) {

                  Result = "敬老の日";

              } else {

                  if (MyDate.getDay() == TUESDAY) {

                      if (MyDay == (MyAutumnEquinox - 1)) {

                          Result = "国民の休日";

                      } else;

                  } else;

              }

          } else {

              if (MyYear >= 1966) {

                  if (MyDay == 15) {

                      Result = "敬老の日";

                  } else;

              } else;

          }

      }

      break;

// １０月 //

  case 10:

      if (MyYear >= 2000) {

          NumberOfWeek = Math.floor(( MyDay - 1) / 7) + 1;

          if ((NumberOfWeek == 2) && (MyDate.getDay() == MONDAY)) {

              Result = "体育の日";

          } else;

      } else {

          if (MyYear >= 1966) {

              if (MyDay == 10) {

                  Result = "体育の日";

              } else;

          } else;

      }

      break;

// １１月 //

  case 11:

      if (MyDay == 3) {

          Result = "文化の日";

      } else {

          if (MyDay == 23) {

              Result = "勤労感謝の日";

          } else {

              if (MyDate.getTime() == cstSokuireiseiden.getTime()) {

                  Result = "即位礼正殿の儀";

              } else;

          }

      }

      break;

// １２月 //

  case 12:

      if (MyDay == 23) {

          if (MyYear >= 1989) {

              Result = "天皇誕生日";

          } else;

      } else;

      break;

  }



  return Result;

}



//===================================================================

// 春分/秋分日の略算式は

// 『海上保安庁水路部 暦計算研究会編 新こよみ便利帳』

// で紹介されている式です。

function prvDayOfSpringEquinox(MyYear)

{

  var SpringEquinox_ret;



  if (MyYear <= 1947) {

      SpringEquinox_ret = 99;    //祝日法施行前

  } else {

      if (MyYear <= 1979) {

          // Math.floor 関数は[VBAのInt関数]に相当

          SpringEquinox_ret = Math.floor(20.8357 +

            (0.242194 * (MyYear - 1980)) - Math.floor((MyYear - 1980) / 4));

      } else {

          if (MyYear <= 2099) {

              SpringEquinox_ret = Math.floor(20.8431 +

                (0.242194 * (MyYear - 1980)) - Math.floor((MyYear - 1980) / 4));

          } else {

              if (MyYear <= 2150) {

                  SpringEquinox_ret = Math.floor(21.851 +

                    (0.242194 * (MyYear - 1980)) - Math.floor((MyYear - 1980) / 4));

              } else {

                  SpringEquinox_ret = 99;    //2151年以降は略算式が無いので不明

              }

          }

      }

  }

  return SpringEquinox_ret;

}



//=====================================================================

function prvDayOfAutumnEquinox(MyYear)

{

  var AutumnEquinox_ret;



  if (MyYear <= 1947) {

      AutumnEquinox_ret = 99; //祝日法施行前

  } else {

      if (MyYear <= 1979) {

          // Math.floor 関数は[VBAのInt関数]に相当

          AutumnEquinox_ret = Math.floor(23.2588 +

            (0.242194 * (MyYear - 1980)) - Math.floor((MyYear - 1980) / 4));

      } else {

          if (MyYear <= 2099) {

              AutumnEquinox_ret = Math.floor(23.2488 +

                (0.242194 * (MyYear - 1980)) - Math.floor((MyYear - 1980) / 4));

          } else {

              if (MyYear <= 2150) {

                  AutumnEquinox_ret = Math.floor(24.2488 +

                    (0.242194 * (MyYear - 1980)) - Math.floor((MyYear - 1980) / 4));

              } else {

                  AutumnEquinox_ret = 99;    //2151年以降は略算式が無いので不明

              }

          }

      }

  }

  return AutumnEquinox_ret;

}


