残業が多い
残業時間のログを残すことで自分の人生のどれだけが仕事に奪われているのか仕事効率化の余地を可視化しようと思います。
事前準備
アプレットの作成
IFTTT で Android Device
と Google Sheets
を連携させて、オフィスの WiFi から切断された時刻を google スプレッドシートに記録するようにします。
実際に使用するのはログ中の OccurredAt
列のみなので2列目以降は適当です。
カレンダー ID の取得
記録を残すための google カレンダーの ID を取得しておきます。
GAS 側での処理
IFTTT の日付フォーマットを整形
IFTTT で日付を記録すると October 01, 2019 at 12:00PM
のような形式でタイムスタンプ記録されます。利用しやすさのため、これを yyyy/mm/dd HH:mm
にフォーマットするために下記の関数を作っておきます。
// IFTTT のタイムスタンプを yyyy/mm/dd HH:mm 形式に整形する関数
function formatIFTTT(timestamp) {
var months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
var m = timestamp.match(/([A-Z][a-z]+) (\d{1,2})\, (\d{4}) at (\d{1,2}):(\d{1,2})([AP]M)/);
var year = m[3];
var month = Number(months.indexOf(m[1])) + 1;
month = ("0" + month).slice(-2);
var date = m[2];
date = ("0" + date).slice(-2);
var hour = Number(m[4]);
if (m[6] == "PM") {
if (hour != 12) {
hour = hour + 12;
}
}
else {
if (hour == 12) {
hour = 0;
}
}
hour = ("0" + hour).slice(-2);
var min = Number(m[5]);
min = ("0" + min).slice(-2);
return (year + "/" + month + "/" + date + " " + hour + ":" + min)
}
メイン処理
- ライブラリは Moment を使用
- 定時は18時として計算
- 時間トリガーで毎日25時に処理実行(それ以降の退社なんて想像したくもない)
→ 「前日の定時」から「実行時点でのログ最終行」までの時間差分を google カレンダーにイベントとして登録
var CALENDAR_ID = PropertiesService.getScriptProperties().getProperty("CALENDAR_ID");
var SHEET_ID = PropertiesService.getScriptProperties().getProperty("SHEET_ID");
var sht = SpreadsheetApp.openById(SHEET_ID).getSheets();
// ログの最終行から残業時間を計算してカレンダーに登録する関数
function getOverWorkTime() {
// 退社時刻
var lastLog = sht[0].getRange(sht[0].getLastRow(), 1).getValue();
var exitTime = Moment.moment(formatIFTTT(lastLog));
// 現在時刻
var now = Moment.moment();
// 定時
var closeTime = now.clone().add(-1, "days").hour(18).minutes(0).second(0);
// 最終退社時刻から定時までの時間
var overWorkSec = exitTime.diff(closeTime, "seconds");
if (overWorkSec <= 0) {
// 負の値=前日の定時以前の退社=残業なし
return;
}
var seconds = Math.floor(overWorkSec);
var h = Math.floor(seconds / 3600); // 時間
var m = Math.floor((seconds % 3600) / 60) + 1; // 分
var event = "残業(" + h + "時間" + m + "分)";
// カレンダーに登録
CalendarApp.getCalendarById(CALENDAR_ID).createEvent(event, closeTime.toDate(), exitTime.toDate());
}
今回の学び
GAS 用の Moment では .add()
や .subtract()
を使用すると元のオブジェクト自体が更新されてしまうようです。回避のためには .clone()
を挟めば良いようです。
コード全体
全文表示
///////////////////////////////////////////////////////
// グローバル変数
///////////////////////////////////////////////////////
var CALENDAR_ID = PropertiesService.getScriptProperties().getProperty("CALENDAR_ID");
var SHEET_ID = PropertiesService.getScriptProperties().getProperty("SHEET_ID");
var sht = SpreadsheetApp.openById(SHEET_ID).getSheets();
///////////////////////////////////////////////////////
// 事前処理
///////////////////////////////////////////////////////
// IFTTTのタイムスタンプをyyyy/mm/dd HH:mm形式に整形する関数
function formatIFTTT(timestamp) {
var months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
var m = timestamp.match(/([A-Z][a-z]+) (\d{1,2})\, (\d{4}) at (\d{1,2}):(\d{1,2})([AP]M)/);
var year = m[3];
var month = Number(months.indexOf(m[1])) + 1;
month = ("0" + month).slice(-2);
var date = m[2];
date = ("0" + date).slice(-2);
var hour = Number(m[4]);
if (m[6] == "PM") {
if (hour != 12) {
hour = hour + 12;
}
}
else {
if (hour == 12) {
hour = 0;
}
}
hour = ("0" + hour).slice(-2);
var min = Number(m[5]);
min = ("0" + min).slice(-2);
return (year + "/" + month + "/" + date + " " + hour + ":" + min)
}
///////////////////////////////////////////////////////
// メイン処理
///////////////////////////////////////////////////////
// ログの最終行から残業時間を計算してカレンダーに登録する関数
function getOverWorkTime() {
// 退社時刻
var lastLog = sht[0].getRange(sht[0].getLastRow(), 1).getValue();
var exitTime = Moment.moment(formatIFTTT(lastLog));
// 現在時刻
var now = Moment.moment();
// 定時
var closeTime = now.clone().add(-1, "days").hour(18).minutes(0).second(0);
// 最終退社時刻から定時までの時間
var overWorkSec = exitTime.diff(closeTime, "seconds");
if (overWorkSec <= 0) {
// 負の値=前日の定時以前の退社=残業なし
return;
}
var seconds = Math.floor(overWorkSec);
var h = Math.floor(seconds / 3600); // 時間
var m = Math.floor((seconds % 3600) / 60) + 1; // 分
var event = "残業(" + h + "時間" + m + "分)";
// カレンダーに登録
CalendarApp.getCalendarById(CALENDAR_ID).createEvent(event, closeTime.toDate(), exitTime.toDate());
}