はじめまして、ますみです!
本記事は、「身の回りの困りごとを楽しく解決!【PR】Works Human Intelligence」のアドベントカレンダー2日目の記事です🎄
今回は、フリーランスエンジニア向けのツールとして**「自分の稼働時間を管理するツール」**の作り方と使い方を紹介します👨💻
私自身は4年ほどフリーランスとして、受託開発やコーチングなどの業務などをしてきましたが「実際にどれくらい各案件ごとに稼働しているのか?」を把握することは非常に重要だと3年目あたりから気付き始めました。
理由としては、以下の3つです。
- 自分の時給単価(市場価値)を正確に把握するため。
- 自分のタイムリソースのマネジメントのため。
- 請求業務を効率化するため。
これに関しては、また別の機会に詳しく書きたいと思います!
いずれにせよ、稼働時間の管理をしっかりとしていない(もしくは全く管理していない)フリーランスエンジニアは意外と周りにいます。そういった方々の働く上での課題を解決するために10分くらいで運用を始められる管理ツールについてまとめてみました!
最終成果物
前置きが長くなりましたが、最終成果物は以下のようなものです。
少し早めのクリスマスプレゼントとして、ソースコードも全て公開していきます🎁
使用技術
今回使用する技術(ツール)は以下の3つです。
- Google Spreadsheet(スプレッドシート)
- Google Calendar(カレンダー)
- Google Apps Script(GAS、ガス)
カレンダーの勤怠情報を、GASを使って抽出して、スプレッドシートへ書き込むという流れになります。
GASが初めての方はこちらをご参照ください👍
稼働管理ツールの作り方と手順
それでは、具体的な手順を説明していきます✨
1. 新しいGoogleスプレッドシートの作成
まずGoogleへログインして、新しいスプレッドシートを作ります。
すごく雑学ですが、実はsheets.new
というURLから新規シートを作成することもできます
2. 大枠を作る
次に、取得してきた情報を見やすくするための大枠を作ります。
以下のように各行のタイトルと取得したい年月のシート名を入力します。
テンプレートのスプレッドシートを以下のURLに置いておきました👍
3. GASでコーディング
「拡張機能 > Apps Script」からGASの編集画面を開きます。
編集画面が開いたら以下の画像のように下記のコードを入力して、保存します。
const ORIGINAL_MENU_NAME = '勤怠管理メニュー';
const GET_CALENDAR_INFO_BUTTON_NAME = '勤怠情報の取得';
const TITLE_NAME = '勤怠管理';
const COMPLETE_PROCESS_TITLE = '勤務表作成完了';
const COMPLETE_PROCESS_MESSAGE = 'お仕事お疲れ様でした。';
const ERROR_TITLE = 'エラー発生';
const ERROR_MESSAGE_INVALID_SHEET_NAME = '無効なシート名です。';
const ERROR_MESSAGE_NO_DATA = '指定月の稼働は、現在ありません。';
const CALENDAR_ID = 'ENTER_HERE@group.calendar.google.com';
/*
【コーディング・ルール】
- 関数:キャメルケース(例:updateCalendarInfo())
- グローバル定数:コンスタントケース(例:ORIGINAL_MENU_NAME)
- その他の定数および変数:スネークケース(例:sheet_name)
*/
function onOpen() {
// オリジナルメニューの追加
// TIPS: スプレッドシートが開いたタイミングで実行されます。
let ui = SpreadsheetApp.getUi();
ui.createMenu(ORIGINAL_MENU_NAME)
.addItem(GET_CALENDAR_INFO_BUTTON_NAME, 'updateCalendarInfo')
.addToUi();
}
function updateCalendarInfo() {
try{
// タイトルの記入(B2セルへ記入)
const sheet_name = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getName(); // 選択中(アクティブ)のシート名を取得
const sheet_title = TITLE_NAME + "(" + sheet_name + ")"; // 月の情報をタイトルに付加
SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getRange(2,2).setValue(sheet_title); // B2セルへタイトルを書き込み
// カレンダーの取得
const my_calendar = CalendarApp.getCalendarById(CALENDAR_ID);
// 選択月の初日と末日を取得
const calc_month_string = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getName() + "/01";
const start_day = new Date(calc_month_string + " 00:00:00");
const end_day = new Date(start_day.getFullYear(), start_day.getMonth()+1, 1);
if (start_day == "Invalid Date"){ // エラー処理:シートの名前が正しくない時
throw(ERROR_MESSAGE_INVALID_SHEET_NAME);
}
// 選択月のカレンダー内の情報(イベント)を取得
const events = my_calendar.getEvents(start_day, end_day);
if (events.length == 0){ // エラー処理:イベントが何もない時
throw(ERROR_MESSAGE_NO_DATA);
}
// カレンダー情報の変数初期化
let record_list = []; // 予定情報の配列(List)
let start_time; // 開始時間(Date)
let end_time; // 終了時間(Date)
let schedule_name = ""; // 予定の名前(String)
let work_time = 0.0; // 勤務時間(Float)
let mtg_time = 0.0; // MTG時間(Float)
let work_time_total = 0.0; // 勤務合計時間(Float)
let mtg_time_total = 0.0; // MTG合計時間(Float)
for(const event of events){
start_time = event.getStartTime();
end_time = event.getEndTime();
schedule_name = event.getTitle();
work_time = (end_time - start_time)/(60*60*1000);
if(schedule_name.match(/MTG/)){
mtg_time = work_time;
}else{
mtg_time = 0;
}
const record = [
start_time,
end_time,
schedule_name,
work_time,
mtg_time,
];
record_list.push(record);
work_time_total = work_time_total + work_time;
mtg_time_total = mtg_time_total + mtg_time;
}
// レコードを書き込み
// TIPS: 一行ずつ書き込むと時間がかかるため、このように配列に格納して、最後にまとめて記入します。
SpreadsheetApp.getActiveSheet().getRange(4,2,record_list.length, record_list[0].length).setValues(record_list);
// 合計時間(全勤務およびMTG)の書き込み
SpreadsheetApp.getActiveSheet().getRange(2,5).setValue(work_time_total); // B5セルへ勤務合計時間を書き込み
SpreadsheetApp.getActiveSheet().getRange(2,6).setValue(mtg_time_total); // B6セルへMTG合計時間を書き込み
Browser.msgBox(COMPLETE_PROCESS_TITLE, COMPLETE_PROCESS_MESSAGE, Browser.Buttons.OK);
return;
}catch(e){
Browser.msgBox(ERROR_TITLE, e, Browser.Buttons.OK);
return;
}
}
4. Google Calendarの作成とIDの埋め込み
以下の手順に沿って、勤怠管理用のGoogle Calendarを作成します。
カレンダーが作成できたら、設定画面から、以下の手順でカレンダーIDをコピーします。
コピーしたカレンダーIDをGASのCALENDAR_ID
の箇所にペーストします。
5. テスト
テストは開発において非常に重要です。
一つずつしっかりと動作しているか確認していきましょう🚀
5-1. 成功パターン
「勤怠管理メニュー > 勤怠情報の取得」を選択して、処理を実行しましょう。
追加した予定がしっかりと反映されているかも確認しましょう。
今回のソースコードでは、MTG
という文字列が入っている場合にMTG時間としても出力されるようにプログラミングされています。
5-2. 例外処理パターン①:シート名が無効な場合
続いて、シート名が2021/12
のように年月のフォーマットではない場合のエラー処理を確認します。
以下のように無効な名前のシート名に変更して、失敗するか確認してみましょう。
5-3. 例外処理パターン②:予定が何も入っていない場合
続いて、カレンダーに何も予定が入っていない場合のエラー処理を確認します。
以下のように、カレンダーに何も予定が入っていない年月のシート名に変更して、失敗するか確認してみましょう。
おすすめの管理方法
最後に、この記事で紹介したスプレッドシートのおすすめの管理方法を紹介します。
私は、2021/temp
というテンプレートのシートを作成して、それをコピーして、各月の勤務管理シート(月次勤怠表のようなもの)を生成するようにしています。
最後に
最後まで読んでくださり、ありがとうございました!
いかがだったでしょうか?
この記事を通して、少しでもあなたの学びに役立てば幸いです!
【仕事の相談はこちら】
お仕事の相談のある方は、下記のフォームよりお気軽にご相談ください。
もしもメールでの問い合わせの方がよろしければ、下記のメールアドレスへご連絡ください。
info*galirage.com(*を@に変えてご送付ください)
🎁 「生成AI活用の無料相談券」もしくは「生成AIの社内ガイドライン(無料PDF)」を『公式LINE』で配布中 🎁
『生成AIを業務に活用したいけど、どうしたらいいかわからない』といった声を多くいただきます。
Galirageでは公式LINEにて、チャットやオンライン会議で「完全個別の生成AI活用無料相談会」を実施しております!
(期間限定で実施しているため、ご興味ある方はお早めに以下のLINE公式アカウントをご登録ください^^)
https://lin.ee/rvz6lMN
※ 予告なく、キャンペーンを終了する可能性がございますが、ご了承ください。
【業務内容】
具体的には、以下のお仕事を中心に受け付けております!(詳しくはこちら)
- 受託開発(例:生成AIを使った社内システムの開発)
- コンサルティング(例:技術戦略のアドバイス)
- 講演(例:社内研修、イベント登壇)
※ 特に「生成AIを使ったシステム開発のご依頼」が多く、ご好評いただいております。
【これまでの相談事例】
以下のようなご相談が多くあります。
🔑 機密情報を漏洩させないための、生成AIのシステム構築をお願いしたい。
🤖 自社データを用いたFAQチャットボットの作り方を知りたい。
💡 ChatGPTを、自分たちの事業にどのように活かせるか、アドバイスやアイデアが欲しい。
おまけ
エンジニアの仲間(データサイエンティストも含む)を増やしたいため、公式LINEを始めました🎉
「一緒に仕事をしてくれる方」「友だちとして仲良くしてくれる方」は、友だち追加をしていただけますと嬉しいです!(仲良くなった人たちを集めて、「ボードゲーム会」や「ハッカソン」や「もくもく会」もやりたいなと考えています😆)
とはいえ、みなさんにもメリットがないと申し訳ないので、特典を用意しました!
友だち追加後に、アンケートに回答してくれた方へ「エンジニア図鑑(職種20選)」のPDFをお送りします◎