FullCalendarの使い方

# FullCalendarの入手

[FullCalendar](https://fullcalendar.io/)に興味があったので触ってみました。

Googleで引っかかる情報はバージョンが古いようで最新版(4.3.1)で検証してみます。
[FullCalendar-4.3.1](https://github.com/fullcalendar/fullcalendar/releases/download/v4.3.1/fullcalendar-4.3.1.zip)

![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324255/d0a18266-df50-4067-98fa-d58823f34af3.png)

とりあえず「Get Started」からzip版をダウンロードしてスタート

![無題2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324255/a4cdc39f-7577-cb9a-b30d-a078d2dbc476.png)

examplesの中にはいろんなタイプのサンプルがあるので
自分好みのベースをチョイスすればよいかな。

![無題3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324255/e3798db0-11be-96b5-4e80-d5220d181805.png)

# FullCarendarのサンプル

- background-events.html
![background-events.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324255/2720d51c-9181-6bfc-7625-5bab830ae4c2.png)

- daygrid-views.html
![daygrid-views.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324255/f05188b2-c0da-6e73-cec3-7fc7aef2f66b.png)

- external-dragging-2cals.html
![external-dragging-2cals.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324255/c3b4ceeb-f0fc-d6d1-4dcb-4322d8aa5b0b.png)

- external-dragging-builtin.html
![external-dragging-builtin.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324255/bd01614d-01e8-35ee-2a38-ecf3b1eed0c5.png)

- full-height.html
![full-height.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324255/573e451c-ba57-e031-f5be-1666d8fe3921.png)

- google-calendar.html
![google-calendar.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324255/6ccb1eb1-a5ff-9c6e-9440-073e66cc2569.png)

- list-views.html
![list-views.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324255/2e7617cd-b6d9-8638-fbe8-19cd5a20386c.png)

- locales.html
![locales.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324255/527dcf6d-fa66-a4c1-38f7-d87066f3e695.png)

- month-view.html
![month-view.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324255/6d277212-41ba-d0be-7807-da6d23cca8f1.png)

- rrule.html
![rrule.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324255/2bfbe14c-59d7-dc8e-ca78-f87270a46251.png)

- selectable.html
![selectable.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324255/8d8771be-4a64-2e1f-3972-4ca765273af2.png)

- theming.html
![theming.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324255/67920014-58cc-72bd-ae98-da11ea647351.png)

- time-zones.html
![time-zones.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324255/494faea8-a9ce-9996-2b47-eea0f425f879.png)

- timegrid-views.html
![timegrid-views.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324255/1d7e417d-4e7d-4ca8-32d5-cbf85d959ce6.png)

- week-numbers.html
![week-numbers.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324255/e58c15de-5fcb-0def-908b-95730d2851ac.png)

# 好みをチョイス
わたしの好みはベース的には「background-events.html」
追加機能として「locales.html」で日本語化したものが最適かな(^^♪

```html:background-events.html
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8' />
<link href="../packages/core/main.css" rel="stylesheet" />
<link href="../packages/daygrid/main.css" rel="stylesheet" />
<link href="../packages/timegrid/main.css" rel="stylesheet" />
<link href="../packages/list/main.css" rel="stylesheet" />
<script src="../packages/core/main.js"></script>
<script src="../packages/interaction/main.js"></script>
<script src="../packages/daygrid/main.js"></script>
<script src="../packages/timegrid/main.js"></script>
<script src="../packages/list/main.js"></script>
<script>

  document.addEventListener('DOMContentLoaded', function() {
    var calendarEl = document.getElementById('calendar');

    var calendar = new FullCalendar.Calendar(calendarEl, {
      plugins: [ 'interaction', 'dayGrid', 'timeGrid', 'list' ],
      header: {
        left: 'prev,next today',
        center: 'title',
        right: 'dayGridMonth,timeGridWeek,timeGridDay,listMonth'
      },
      defaultDate: '2019-08-12',
      navLinks: true, // can click day/week names to navigate views
      businessHours: true, // display business hours
      editable: true,
      events: [
        {
          title: 'Business Lunch',
          start: '2019-08-03T13:00:00',
          constraint: 'businessHours'
        },
        {
          title: 'Meeting',
          start: '2019-08-13T11:00:00',
          constraint: 'availableForMeeting', // defined below
          color: '#257e4a'
        },
        {
          title: 'Conference',
          start: '2019-08-18',
          end: '2019-08-20'
        },
        {
          title: 'Party',
          start: '2019-08-29T20:00:00'
        },

        // areas where "Meeting" must be dropped
        {
          groupId: 'availableForMeeting',
          start: '2019-08-11T10:00:00',
          end: '2019-08-11T16:00:00',
          rendering: 'background'
        },
        {
          groupId: 'availableForMeeting',
          start: '2019-08-13T10:00:00',
          end: '2019-08-13T16:00:00',
          rendering: 'background'
        },

        // red areas where no events can be dropped
        {
          start: '2019-08-24',
          end: '2019-08-28',
          overlap: false,
          rendering: 'background',
          color: '#ff9f89'
        },
        {
          start: '2019-08-06',
          end: '2019-08-08',
          overlap: false,
          rendering: 'background',
          color: '#ff9f89'
        }
      ]
    });

    calendar.render();
  });

</script>
<style>

  body {
    margin: 40px 10px;
    padding: 0;
    font-family: Arial, Helvetica Neue, Helvetica, sans-serif;
    font-size: 14px;
  }

  #calendar {
    max-width: 900px;
    margin: 0 auto;
  }

</style>
</head>
<body>

  <div id='calendar'></div>

</body>
</html>
```

```html:locales.html
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8' />
<link href="../packages/core/main.css" rel="stylesheet" />
<link href="../packages/daygrid/main.css" rel="stylesheet" />
<link href="../packages/timegrid/main.css" rel="stylesheet" />
<link href="../packages/list/main.css" rel="stylesheet" />
<script src="../packages/core/main.js"></script>
<script src="../packages/core/locales-all.js"></script>
<script src="../packages/interaction/main.js"></script>
<script src="../packages/daygrid/main.js"></script>
<script src="../packages/timegrid/main.js"></script>
<script src="../packages/list/main.js"></script>
<script>

  document.addEventListener('DOMContentLoaded', function() {
    var initialLocaleCode = 'en';
    var localeSelectorEl = document.getElementById('locale-selector');
    var calendarEl = document.getElementById('calendar');

    var calendar = new FullCalendar.Calendar(calendarEl, {
      plugins: [ 'interaction', 'dayGrid', 'timeGrid', 'list' ],
      header: {
        left: 'prev,next today',
        center: 'title',
        right: 'dayGridMonth,timeGridWeek,timeGridDay,listMonth'
      },
      defaultDate: '2019-08-12',
      locale: initialLocaleCode,
      buttonIcons: false, // show the prev/next text
      weekNumbers: true,
      navLinks: true, // can click day/week names to navigate views
      editable: true,
      eventLimit: true, // allow "more" link when too many events
      events: [
        {
          title: 'All Day Event',
          start: '2019-08-01'
        },
        {
          title: 'Long Event',
          start: '2019-08-07',
          end: '2019-08-10'
        },
        {
          groupId: 999,
          title: 'Repeating Event',
          start: '2019-08-09T16:00:00'
        },
        {
          groupId: 999,
          title: 'Repeating Event',
          start: '2019-08-16T16:00:00'
        },
        {
          title: 'Conference',
          start: '2019-08-11',
          end: '2019-08-13'
        },
        {
          title: 'Meeting',
          start: '2019-08-12T10:30:00',
          end: '2019-08-12T12:30:00'
        },
        {
          title: 'Lunch',
          start: '2019-08-12T12:00:00'
        },
        {
          title: 'Meeting',
          start: '2019-08-12T14:30:00'
        },
        {
          title: 'Happy Hour',
          start: '2019-08-12T17:30:00'
        },
        {
          title: 'Dinner',
          start: '2019-08-12T20:00:00'
        },
        {
          title: 'Birthday Party',
          start: '2019-08-13T07:00:00'
        },
        {
          title: 'Click for Google',
          url: 'http://google.com/',
          start: '2019-08-28'
        }
      ]
    });

    calendar.render();

    // build the locale selector's options
    calendar.getAvailableLocaleCodes().forEach(function(localeCode) {
      var optionEl = document.createElement('option');
      optionEl.value = localeCode;
      optionEl.selected = localeCode == initialLocaleCode;
      optionEl.innerText = localeCode;
      localeSelectorEl.appendChild(optionEl);
    });

    // when the selected option changes, dynamically change the calendar option
    localeSelectorEl.addEventListener('change', function() {
      if (this.value) {
        calendar.setOption('locale', this.value);
      }
    });

  });

</script>
<style>

  body {
    margin: 0;
    padding: 0;
    font-family: Arial, Helvetica Neue, Helvetica, sans-serif;
    font-size: 14px;
  }

  #top {
    background: #eee;
    border-bottom: 1px solid #ddd;
    padding: 0 10px;
    line-height: 40px;
    font-size: 12px;
  }

  #calendar {
    max-width: 900px;
    margin: 40px auto;
    padding: 0 10px;
  }

</style>
</head>
<body>

  <div id='top'>

    Locales:
    <select id='locale-selector'></select>

  </div>

  <div id='calendar'></div>

</body>
</html>
```

なるほど`locale: initialLocaleCode,`だから`locale: 'ja',`で良さそうですね。

# FullCarendarを日本語化したい。

## 日付、曜日、時間を日本語化

```javascript:mycalendar.html
    var calendar = new FullCalendar.Calendar(calendarEl, {
      plugins: [ 'interaction', 'dayGrid', 'timeGrid', 'list' ],
      header: {
        left: 'prev,next today',
        center: 'title',
        right: 'dayGridMonth,timeGridWeek,timeGridDay,listMonth'
      },
      defaultDate: '2019-08-12',
      navLinks: true, // can click day/week names to navigate views
      businessHours: true, // display business hours
      editable: true,
      events: [
        {
```

これを

```javascript:mycalendar.html
    var calendar = new FullCalendar.Calendar(calendarEl, {
      plugins: [ 'interaction', 'dayGrid', 'timeGrid', 'list' ],
      header: {
        left: 'prev,next today',
        center: 'title',
        right: 'dayGridMonth,timeGridWeek,timeGridDay,listMonth'
      },
      locale: 'ja',
      defaultDate: '2019-08-12',
      navLinks: true, // can click day/week names to navigate views
      businessHours: true, // display business hours
      editable: true,
      events: [
        {
```

とすると、これが
![background-events.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324255/2acf1001-0566-bdfe-8b15-efaa818d6ca0.png)

こうなりました。
![mycalendar01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324255/1cdd770c-0f8d-de7d-9b5f-0238e857a7f3.png)

## 上部のメニューの日本語化

どうせなら上部のtoday、month、week、day、listも日本語化したいですよね。
本格的なlocalesのjsを追加します。

```html:mycalendar.html
<script src="../packages/core/locales-all.js"></script>
```

![mycalendar02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324255/79b2de0b-6136-764d-47a0-35df29d76a0a.png)

## 土日の色付け
因みに土日の色付けは`businessHours:`でコントロールされています。
土日の色付けを消したい場合は`businessHours: false,`で消えるようです。

消してみた(^^♪

![mycalendar03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324255/4d6db63a-45bf-b3fe-9d08-112a556fcfcc.png)


## 月をずらすボタン＜＞を変えてみる
先月、来月に移動するボタンはデフォルトで＜＞となっていますが
これを日本語化もできます。

`buttonIcons:`でコントロールされているので`buttonIcons: false`とします。

```javascript:mycalendar.html
      locale: 'ja',
      defaultDate: '2019-08-12',
```

設定してみるとこんな感じ

```javascript:mycalendar.html
      locale: 'ja',
      buttonIcons: false, // show the prev/next text
      defaultDate: '2019-08-12',
```

![mycalendar04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324255/c2f304bd-268f-6612-05dd-5269fef3c9d0.png)

うん。好みが判れそう(笑)
わたしは＜＞でいいかな。

## timezoneの設定

[docs::timeZone](https://fullcalendar.io/docs/timeZone)

timezoneの設定は`timeZone:`で指定します。
`timeZone: 'Asia/Tokyo'`
これにより`events`の時間表記が
　**2018-09-01T12:30:00+09:00**
といった形式から
　**2018-09-01T12:30:00**
だけにできます。

まあ`timeZone: 'locale'`がデフォルトなので日本圏でのみのサイトなら指定しなくても良いでしょうが…

```javascript:mycalendar.html
    var calendar = new FullCalendar.Calendar(calendarEl, {
      plugins: [ 'interaction', 'dayGrid', 'timeGrid', 'list' ],
      header: {
        left: 'prev,next today',
        center: 'title',
        right: 'dayGridMonth,timeGridWeek,timeGridDay,listMonth'
      },
      timeZone: 'Asia/Tokyo',
      locale: 'ja',
      defaultDate: '2019-08-12',
      navLinks: true, // can click day/week names to navigate views
      businessHours: true, // display business hours
      editable: true,
      events: [
        {
```

## カレンダーの表示時間はhh:mm形式にしたい

日本語化するとカレンダー内のイベント時刻も「ｘｘ時」と表示されます。
これをhh:mm形式にしたい場合は以下の様に修正します。
場所は何処でも良さそうですが`eventTimeFormat`を指定します。

```javascript:mycalendar.html
        {
          start: '2019-08-06',
          end: '2019-08-08',
          overlap: false,
          rendering: 'background',
          color: '#ff9f89'
        }
      ],
      eventTimeFormat: { hour: 'numeric', minute: '2-digit' }
```

これが
![mycalendar01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324255/f97685d2-e6ac-2c93-9d1e-46a685259893.png)

こうなります。ちょっとスッキリするかも

![mycalendar05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324255/d1a3c25a-bce5-c79b-d06d-50f9b6b26589.png)

## デフォルト表示の切り替え
デフォルトのViewの切り替えは文字通り`defaultView`にて行います。
例えば管理画面などはカレンダー表示よりリスト表示の方が良いこともありますよね。
そんな時はこんな感じで

```javascript:mycalendar.html
      defaultView: 'listMonth',
```

# eventsの書き方

## 通常イベント(時間枠)

`Party`の方は通常イベント。デフォルトでは`end`を指定しないと1時間枠となります。

```js:events
        {
          title: 'Party(1h)',
          start: '2019-08-29T20:00:00'
        },
        {
          title: 'Party(1.5h)',
          start: '2019-08-29T18:00:00',
          end: '2019-08-29T19:30:00'
        },
```

## 通常イベント(終日枠)

`Conference`の方は複数日をまたがるイベント。終了日の`end`を指定しないとその日一日の終日イベントとなります。

```js:events
        {
          title: 'Conference',
          start: '2019-08-18',
          end: '2019-08-20'
        },
        {
          title: 'Party(1day)',
          start: '2019-08-28T20:00:00'
        },
```

## 受付できない期間

`overlap: false`でそこに予定がドロップできなくなります。
また、禁止期間が判りやすいようにcolorを指定していますね。

```js:events
        {
          start: '2019-08-06',
          end: '2019-08-08',
          overlap: false,
          rendering: 'background',
          color: '#ff9f89'
        }
```

## 特定イベントのみ登録できる期間

`constraint: 'xxx'`を指定した場合は、`groupId: 'xxx'`で指定した期間にのみ登録できるようです。

```js:events
        {
          title: 'Meeting',
          start: '2019-08-13T11:00:00',
          constraint: 'availableForMeeting', // defined below
          color: '#257e4a'
        },
        // areas where "Meeting" must be dropped
        {
          groupId: 'availableForMeeting',
          start: '2019-08-11T10:00:00',
          end: '2019-08-11T16:00:00',
          rendering: 'background'
        },
        {
          groupId: 'availableForMeeting',
          start: '2019-08-13T10:00:00',
          end: '2019-08-13T16:00:00',
          rendering: 'background'
        },
```

## 特定イベントのみ登録できる期間(平日日勤帯)

`constraint: 'businessHours'`とした場合、月～金の9:00-17:00までがデフォルトで登録可能のようです。
ただし、カレンダーオプションで`businessHour: true`とする必要があります。

```javascript:mycalendar.html
      businessHours: true, // display business hours
```

```js:events
        {
          title: 'Business Lunch',
          start: '2019-08-03T13:00:00',
          constraint: 'businessHours'
        },
```

## `businessHour`を定義する

[Docs :: Business Hours](https://fullcalendar.io/docs/business-hours)

出社時間や曜日を指定する際は以下のようにします。

```javascript:mycalendar.html
      businessHours: true, // display business hours
```

我が社は月～金 9:30-18:00ですのでこんな感じ。

```javascript:mycalendar.html
      businessHours: {
        // days of week. an array of zero-based day of week integers (0=Sunday)
        daysOfWeek: [ 1, 2, 3, 4, 5 ],
        startTime: '9:30',
        endTime: '18:00'
      },
```

# イベント

## カレンダーが表示されたらデータを取ってきたい

カレンダーは基本1か月分しか表示しないので「＜」「＞」や「今日」を押したときにデータを持ってきたいですよね。

どうやら標準的な機能で網羅されているようでした。
以下のように`events`を動的にjsonを出力するphp等を指定すると**GET**でパラメータ付きで自動的にCallしてくれます。

下記のようにした場合、./getEvents.phpは次のように呼ばれます。

```
./getEvents.php?start=2019-12-29T00%3A00%3A00&end=2020-02-09T00%3A00%3A00&timeZone=Asia%2FTokyo
```

| param  | value              |
|:-------|:-------------------|
|start   |2019-12-29T00:00:00 |
|end     |2020-02-09T00:00:00 |
|TimeZone|Asia/Tokyo          |


```javascript:mycalendar.html
document.addEventListener('DOMContentLoaded', function() {
    var calendarEl = document.getElementById('calendar');

    var calendar = new FullCalendar.Calendar(calendarEl, {
      plugins: [ 'dayGrid', 'timeGrid', 'bootstrap' ],
      locale: 'ja',
      timeZone: 'Asia/Tokyo',
      themeSystem: 'bootstrap',
      businessHours: true, // display business hours
      header: {
        left: 'prev,next today',
        center: 'sMeeting説明会',
        right: 'dayGridMonth,timeGridWeek,timeGridDay,listMonth'
      },
      weekNumbers: false,
      navLinks: true, // can click day/week names to navigate views
      editable: false,
      eventLimit: true, // allow "more" link when too many events
      events: './getEvents.php'
    });

    calendar.render();
  });
```



~~そんな時は`datesRender`イベントを活用すると実現できそう。
このイベントViewが変わると呼ばれますのでグローバル変数で現在の開始終了日時を確保しておき、その範囲外の場合はeventsを取ってくるという具合です。
まだ勉強不足で動的なイベント生成からの描画は未実装ですが、カレンダーの「＜」「＞」や「今日」を押したときはconsole.logに取得すべき日時範囲が出力されます。~~

```javascript:mycalendar.html
  var dateStart = null;
  var dateEnd = null;

  document.addEventListener('DOMContentLoaded', function() {
    var calendarEl = document.getElementById('calendar');

    var calendar = new FullCalendar.Calendar(calendarEl, {
      plugins: [ 'interaction', 'dayGrid', 'timeGrid', 'list' ],
      header: {
        left: 'prev,next today',
        center: 'title',
        right: 'dayGridMonth,timeGridWeek,timeGridDay,listMonth'
      },
      locale: 'ja',
      buttonIcons: false, // show the prev/next text
      defaultDate: '2019-08-12',
      navLinks: true, // can click day/week names to navigate views
      businessHours: {
        daysOfWeek: [ 1, 2, 3, 4, 5 ],
        startTime: '9:30',
        endTime: '18:00'
      },
      editable: true,
      eventLimit: true, // allow "more" link when too many events    
      eventTimeFormat: { hour: 'numeric', minute: '2-digit' },

      datesRender: function(info) {
        var ds = info.view.activeStart.toJSON();
        var de = info.view.activeEnd.toJSON();
        if( ( dateStart == null || Date.parse(dateStart) > Date.parse(ds)) || ( dateEnd == null || Date.parse(dateEnd) < Date.parse(de) ) ){
          dateStart = ds;
          dateEnd = de;
          console.log('render:'+ds+" - "+de);
        }
      }
    });

    calendar.render();
  });
```

## eventをクリックして業務アプリと連携したい

[Docs : Event Object](https://fullcalendar.io/docs/event-object)

eventをクリックした際に業務アプリケーション側にそのイベントを渡したいって事ちょいちょいありますよね。
そんな時はこんな感じで実装すると良さそう。

まずeventsにはeventを一意に特定するキー情報を付与します。（`id`: UUIDとか）
この`id`というアトリビュートはカレンダー標準でもっているアトリビュートです。
カレンダーはeventに独自のパラメータを拡張し保持することもできます。
例えばステータスといったものを追加します。(`status`)
するとカレンダーに登録する際のJSONはこんな感じ。

```JS:events
        {
          id: '262399c4-3d9c-4d4f-b090-c8d8e8b50358',
          title: 'Business Lunch',
          start: '2019-08-03T13:00:00',
          status: 'finished'
        },
        {
          id: '3a05c506-3e5a-4e33-bd9e-e2a92ae37e27',
          title: 'Business Lunch',
          start: '2019-08-03T13:00:00',
          status: 'resered'
        },
```

この登録したevent情報をクリックしたときに受け取りたい場合、こんな感じ。

```javascript:mycalendar.html
      eventRender: function(info) {
        info.el.onclick=function(){
          alert(info.event.id + ":" + info.event.extendedProps.status);
        };
      }
    });
```

eventRenderでeventを描画する際にcallback関数を仕込みます。

上の例では...
eventは引数であるinfo.elで参照できるので、onclick時にcallback関数を仕込んでいます。
eventの情報は`info.event.*`で参照できますので、カレンダー組み込みのアトリビュート
例えば`id`なら`info.event.id`で参照できます。
先ほど拡張した`status`はというと`info.event.extendedProps.*`で参照できます。
つまり`info.event.extendedProps.status`ですね。

今回は単純にalertでeventの属性情報を表示するのみとしていますが
ajaxで情報取得し編集画面を表示するもよし、画面遷移で編集画面にするもよし
活用シーンは色々あると思います。


## カレンダーに登録されているイベントを引っ張ってきたい
カレンダーオブジェクトに定義されているイベント情報を引っ張ってきてJQueryなどで利用したいシーンもあるかも
例えば予約フォームをモーダルで表示して日付、時間が変更されたのを契機に既存イベントと重複しないかチェックとか

そんな場合はこのようにします。

```javascript
var events = calendar.getEvents();
for(var i=0; i<events.length; i++){
  alert(events[i].title + "..." + events[i].start);
}
```

取れるenentオブジェクトのプロパティはこちらからどうそ

[Docs : event object](https://fullcalendar.io/docs/event-object)

```html:mycalendar.html
<script>

  var calendar = null;    // calendarオブジェクトをグローバル変数にしておく

  document.addEventListener('DOMContentLoaded', function() {
    var calendarEl = document.getElementById('calendar');

    calendar = new FullCalendar.Calendar(calendarEl, {   // varをカットしグローバル変数を利用
      plugins: [ 'interaction', 'dayGrid', 'timeGrid' ],
      header: {
        left: 'prev,next today',
        :
</script>
:
<!-- html -->
:
<script>
$('#EntryDate').on('change',function(){
  if( /^[0-9]{4}\/[0-9]{2}\/[0-9]{2}$/.test($(this).val()) ){
    checkEntryDateTime( $(this).val(), $('#EntryTime').val() );
  } else {
    $('#errmsg').text('平日受付可能日を選択してください');
    $('#entry_errmsg').addClass('show');
  }
});

$('#EntryTime').on('change',function(){
  if( /^[0-9]{4}\/[0-9]{2}\/[0-9]{2}$/.test($('#EntryDate').val()) ){
    checkEntryDateTime( $('#EntryDate').val(), $(this).val() );
  }
});

function checkEntry(d, t){    // d:YYYY/MM/DD, t:hh:mm
  if( d && t ){
    dd = new Date(d);
    dt = new Date(d + " " + t + ":00");

    // 予約重複確認
    var events = calendar.getEvents();    // calendarオブジェクトからイベントを取得
    for(var i=0; i<events.length; i++){
      if( events[i].start == dt ){
        $('#errmsg').text('受付が重複しています。受付可能日の空いている日時を選択してください');
        $('#entry_errmsg').addClass('show');
      } else if ( events[i].id == 'nonReception' && events[i].start == dd ){
        $('#errmsg').text('受付可能日を選択してください');
        $('#entry_errmsg').addClass('show');
     }
    }
  }
}
</script>
```

実際に実験してみたのですが…どうも`events`に定義している日時と
`getEvents()`で取ったイベントの日時の時間がずれてて使い物になりませんでした…。

calendarのeventsで定義した値

| param  | value              |
|:-------|:-------------------|
|title|Business Lunch|
|start|2019-08-03T13:00:00 |
|constraint|businessHours|

実際にeventsで取得した時の値

| param  | value              |
|:-------|:-------------------|
|events[0].start|Sat Aug 03 2019 22:00:00 GMT+0900 |
|events[0].title|Business Lunch|

見事に09:00分足されてますよね...
`TimeZone`の定義がおかしいのかなぁ

### 時間ズレの原因判明

上記時間ズレの原因が判明しました♪
原因は`locale`で定義したうえで更に`timeZone`の定義をしていたためでした。
下記の通り、`timeZone`の定義をコメントアウトすればちゃんとカレンダー表示通りの時間が返ってきます。

```html:mycalendar.html
<script>
  var calendar = null;

  document.addEventListener('DOMContentLoaded', function() {
    var calendarEl = document.getElementById('calendar');

    calendar = new FullCalendar.Calendar(calendarEl, {
      plugins: [ 'interaction', 'dayGrid', 'timeGrid' ],
      header: {
        left: 'prev,next today',
        center: 'title',
        right: 'dayGridMonth,timeGridWeek,timeGridDay'
      },
      locale: 'ja',
//      timeZone: 'Asia/Tokyo',
      defaultDate: '2019-08-12',
      navLinks: true, // can click day/week names to navigate views
      businessHours: true, // display business hours
      editable: true,
      events: [
        {
          id: 'event',
          title: 'Business Lunch',
          start: '2019-08-03T13:00:00',
          constraint: 'businessHours'
        }
      ],
      eventTimeFormat: { hour: 'numeric', minute: '2-digit' }
    });

    calendar.render();
  });

</script>
```



## まだまだ
まだまだ色々ありそうなので、必要そうで分かり次第アップデートしていきます。




# 最後に

他にも一杯オプションがあります。

[FullCalendar :: doc](https://fullcalendar.io/docs)