Site icon Tips Note by TAM

Google Calender iCal形式のデータから、日本の祝日リストを自動生成する

前回の記事の続き。
jQuery ui Datepickerに祝日を反映する
祝日を反映したのはいいけど、祝日リストを直書きするのは大変だなということで、
こんな方法はどうでしょうか。

はじめに

まずどこかに都合のいい日本の祝日APIみたいやつないかなぁ。というところから始まり、
以下のようなイメージを持ちました。

  • 祝日データを探す…
  • それをなんとか取得し、都合の良い配列に整形する
  • JSONファイルにする
  • キャッシュする

Google Calenderを活用する

お世話になりっぱなしのGoogleに日本の祝日データを提供していただくことにしました。
なんとiCal形式であれば取得できるので、PHPのfile_get_contentsを使って取得し、なんとかします。

<?php

  /**
   * JSON 生成
   * @param $ical_url
   */
  function creat_holiday_json($ical_url)
  {

      $dates = [];

      // iCal データの取得
      $ics = file_get_contents($ical_url);
      if (empty($ics)) {
          return false;
      }

      // イベントごとに区切って配列化
      $events = explode('END:VEVENT', str_replace("\r", '', $ics));

      // 日付を求める
      foreach ($events as $i => $event) {
          if (preg_match('/DTSTART;\D*(\d+)/m', $event, $date) != 1) {
              continue;
          }
          $datetime = strtotime($date[1]);
          $dates[$i] = date('Ymd', $datetime);
      }

      // 日付 昇順にソートして返却
      sort($dates);
      file_put_contents('holiday.json', json_encode($dates, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
  }

  $ical_url  = 'https://calendar.google.com/calendar/ical/japanese__ja@holiday.calendar.google.com/public/full.ics';
  creat_holiday_json($ical_url);

これでJSONファイル生成ができました!

JSONファイルをキャッシュさせる

ただページにアクセスされる度に、毎回この処理が行われるのは非効率なので、
JSONファイルを生成した時間が、ある一定期間経過していたら処理されるしたい。
そこで、PHPのfilemtime関数で、JSONファイルの最終更新日を確認するようにしました。

<?php

  /**
   * JSON 生成
   * @param $ical_url
   * @return array|false
   */
  function get_date_from_ics($ical_url)
  {

      $dates = [];

      // iCal データの取得
      $ics = file_get_contents($ical_url);
      if (empty($ics)) {
          return false;
      }

      // イベントごとに区切って配列化
      $events = explode('END:VEVENT', str_replace("\r", '', $ics));

      // 日付を求める
      foreach ($events as $i => $event) {
          if (preg_match('/DTSTART;\D*(\d+)/m', $event, $date) != 1) {
              continue;
          }
          $datetime = strtotime($date[1]);
          $dates[$i] = date('Ymd', $datetime);
      }

      // 日付 昇順にソートして返却
      sort($dates);

      return $dates;
  }

  /**
   * jsonファイルの最終更新日を見て、毎月更新される。
   * @param $file_path
   * @param $ical_url
   */
  function holiday_json_write($file_path, $ical_url)
  {

      // 現在日時を取得
      $now_time = date('Ym');
      $file_time = '';

      // 最終更新日の取得
      if(file_exists($file_path)){
          $file_timestamp = filemtime($file_path);
          $file_time = date('Ym', $file_timestamp);
      }

      // 年月の文字列で比較して、月一更新されるようにする
      $time = $file_time - $now_time;
      if($time < 0) {
          $holidays = get_date_from_ics($ical_url);
          file_put_contents($file_path, json_encode($holidays, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
      }
  }

  $file_path    = 'holiday.json';
  $ical_url  = 'https://calendar.google.com/calendar/ical/japanese__ja@holiday.calendar.google.com/public/full.ics';
  holiday_json_write($file_path, $ical_url);

※こちらの例では、今日から数えて1ヶ月以上古かったら更新されるようになります。

これでようやく問題解決です!

生成したJSONファイルにアクセスする

あとは、こちらのjsonファイルをJSで$.ajaxもしくは、$.getJSONで処理してあげれば
.complete()以降は同じです。

<script>
  var holidays = [];
  $.getJSON('holiday.json' , function(json) {
    var value;
    Object.keys(json).forEach(function(key) {
        value = this[key];
        holidays.push(value);
    }, json);
  }).complete(function(){
    $('#datepicker').datepicker({
        dayNamesMin: ['SUN','MON','TUE','WED','THU','FRI','SAT'],
        beforeShowDay: function(date) {
            var disable;
            var editedDate = date.getFullYear() + ('0' + (date.getMonth() + 1)).slice(-2) + ('0' + date.getDate()).slice(-2);

            for (var i = 0; i < holidays.length; i++) {
                disable = holidays[i];
                if (editedDate == disable) return [true, 'ui-datepicker-week-end'];
            }
            return [true, ''];
        }
    });
});
</script>

カレンダーUIが必要で、祝日反映する機会は結構あるかなぁと思うので
何かの参考になれば幸いです。

【参考】
・option-beforeShowDay
http://api.jqueryui.com/datepicker/#option-beforeShowDay
・getjson
http://api.jquery.com/jquery.getjson/