2015年7月23日木曜日

Googleカレンダーを元にした作業実績を作成する

こんにちは、井下です。

いよいよ近所の公園でもセミの声が聞こえてきましたが、みなさんの周りはいかがでしょうか?
通勤ルートに小学校があるのですが、彼らは夏休みを満喫中なんですよね。なんとも羨ましい…。

さて、今回は前回予告していた通り、Googleカレンダーを元にして、作業実績を作成します。

イメージ図(前回のものを再掲)



Googleのサービスの関係は下記の図のようになります。



では、実現したコードを見てみましょう。
HOUR_MILLISECOND = 60 * 60 * 1000;
DATE_MILLISECOND = 24 * HOUR_MILLISECOND;

function run() {
  // 出力先スプレッドシートとシートの設定
  var SSHEET_ID = "XXXXXXXXXXXXXXXXXXXXXXXXXXXX";
  var SHEET_NAME = "YYYYY"

  // 出力先スプレッドシートのシートを取得
  var sheet = SpreadsheetApp.openById(SSHEET_ID).getSheetByName(SHEET_NAME);

  // 日付範囲の設定
  var DATE_TERM = 5;
  var startDate = new Date("2015/7/20");
  var endDate = new Date(startDate.getTime() + DATE_TERM * DATE_MILLISECOND);

  // デフォルト(初期表示)されるカレンダーを選択
  var cal = CalendarApp.getDefaultCalendar();

  // カレンダーのイベントを取得
  var events = cal.getEvents(startDate, endDate);

  var row = 0;
  var column = 0;
  var works = [""];
  var result = [[""]];

  for(var index in events) {
    // イベントの名前、作業時間、実施日を取得
    var title = events[index].getTitle();
    var workTime = getWorkTime(events[index]);
    var targetDate = getTargetDate(events[index]);
 
    // イベントの名前がループ中に出てきたかを確認
    row = works.indexOf(title);
 
    // イベントの名前がループ中初めて出てきた場合
    if(row == -1){
      row = works.length;
      result[row] = [];
      result[row][0] = title;
   
      works.push(title);
    }
 
    // イベントの実施日がループ中初めて出てきた場合
    if(index == 0 || targetDate != getTargetDate(events[index - 1])){
      column++;
      result[0][column] = targetDate;
    }

    result[row][column] = result[row][column] == null ? workTime : workTime + result[row][column];
  }

  sheet.clear();

  // 1行目(日付表示の行)の取得・書き込み
  var header =  getDateRow(result[0]);
  sheet.getRange(1, 1, 1, header.length).setValues(new Array(header));

  // 2行目以降の取得・書き込み
  for(var sRow = 1; sRow < result.length; sRow++) {
    var writeRow = getWriteRow(result[sRow]);
    sheet.getRange(sRow + 1, 1, 1, writeRow.length).setValues(new Array(writeRow));
  }
}

function getDateRow(arrray){
  var dateRow = arrray;
  dateRow.splice(1, 0, "合計");

  return dateRow;
}

function getWriteRow(arrray){
  var writeRow = replaceArrayNull(arrray);
  var totalWorkTime = getTotalWorkTime(arrray);
  writeRow.splice(1, 0, totalWorkTime);

  return writeRow;
}

function replaceArrayNull(arrray){
  for(var index = 0; index < arrray.length; index++){
    if(arrray[index] == null){
      arrray[index] = "";
    }
  }
  return arrray;
}

function getTotalWorkTime(arrray){
  var total = 0;

  for(var index = 0; index < arrray.length; index++){
    if(isFinite(arrray[index]) && arrray[index] != ""){
      total += arrray[index];
    }
  }
  return total;
}

function getWorkTime(event){
  return (event.getEndTime() - event.getStartTime()) / HOUR_MILLISECOND;
}

function getTargetDate(event){
  var sourceDate = event.getStartTime();
  return (sourceDate.getMonth() + 1) + "/" + sourceDate.getDate();
}

赤字部分は実行環境に応じて必ず書き換えてください。
なお、"SSHEET_ID"には出力先として指定するスプレッドシートのIDを指定し、そのスプレッドシートのどのシートに出力するかを、"SHEET_NAME"(こちらはシート)に指定します。
青字部分は実行時の都合に応じて書き換えてください。
カレンダーから抜き出す情報の開始日を"startDate"に指定し、開始日から何日分を取得するかを"DATE_TERM"に指定します。

実際に次のようなカレンダーに対して実行すると…

こんな感じに出力されました。


カレンダーの画像が小さくて分かりづらいですが、同じ作業が別の日にあった場合、行は1つに統一するようになっています。(具体的には"打ち合わせ"が7/21と7/24にあるところと、"開発"が7/22と7/24にあるところです)

なお、イベントが1つもない日(上記の図で言えば7/23)は、列が作成されない仕様なので、その点は注意してください。
他に注意するべき仕様として、終日の予定は24時間としてカウントします。

全ての予定と実績をGoogleカレンダーに書き込んでいる方は稀だと思いますが、日常的にGoogleカレンダーを業務で利用している方は、本当の作業実績を作成するための一助としてご利用ください。

0 件のコメント:

コメントを投稿