stephen-kraakmo-uAzUg6_tMCo-unsplash

タイムトラッカーアプリClockifyのタイムエントリ(時間記録) をAPIでGoogleカレンダーにコピーする その3 – クエリパラメータを指定して前日のエントリのみを取得する

freeeに関係ない話題ですが、Google Apps Script(以下GAS)でできる効率化の例として番外編としてfreee API以外のGASでの活用に関しても記事にしています。

今回は、「ある1日にどんな作業にどれだけ時間を使ったのか記録するタイムトラッカーアプリであるClockifyのタイムエントリ(時間記録)をGoogleカレンダーにコピーしてライフログにする」に挑戦したいと思います。

前回の記事では、Time entry(時間記録)の取得に必要なUser IDとWorkspace IDを取得して、プロパティストアにするところまで紹介しました。

Time entryのエンドポイントにリクエストを送信してみる

まず、今回取得したいデータ種別であるTime entry(時間記録)の個別エンドポイントを公式ドキュメントで確認します。

共通エンドポイントに個別エンドポイントを結合して、クエリパラメータ(絞り込み条件)の指定なしでリクエストを送信します。

function logTimeEntries() {
  const apiKey = PropertiesService.getScriptProperties().getProperty('CLOCKIFY_API_KEY'); // API Keyはプロパティストアに格納
  const workspaceId = PropertiesService.getScriptProperties().getProperty('CLOCKIFY_WORKSPACE_ID'); // Workspace IDはプロパティストアに格納
  const userId = PropertiesService.getScriptProperties().getProperty('CLOCKIFY_USER_ID'); // User IDはプロパティストアに格納
  const baseUrl = 'https://api.clockify.me/api/v1'
  const url = `${baseUrl}/workspaces/${workspaceId}/user/${userId}/time-entries`;

  /* Class UrlFetchApp のリファレンスからfetch(url, params)メソッドを確認しパラメーターの書き方を読み替える */
  const params = {
    contentType: 'application/json',
    headers: { 'X-Api-Key': apiKey },
    muteHttpExceptions: true // レスポンスが失敗した場合でもエラーを出さずにHTTPResponseを返すオプション
  };

  const response = UrlFetchApp.fetch(url, params); // HTTPResponse
  const json = response.getContentText(); // HTTPResponseの内容の文字列 = JSON文字列
  const aryObj = JSON.parse(json); // JSON文字列をJSONオブジェクトにparse(解析)
  console.log(aryObj.length);
  console.log(aryObj);
}

リクエストが成功して以下のようにログ出力されました。

今回はクエリパラメータ(絞り込み条件)なしだったので、取得上限のデフォルト数である50件のタイムエントリが取得できています。

クエリパラメータ(絞り込み条件)を指定してタイムエントリを絞り込む

クエリパラメータ(絞り込み条件)を指定することで、取得するデータを絞り込むことができます。Time entryのエンドポイントで指定できるクエリパラメータ(絞り込み条件)は以下の通りになります。

  • description:概要でフィルタリング
  • start:開始日時(ISO-8601形式)
  • end:終了日時(ISO-8601形式)
  • project:プロジェクトでフィルタリング
  • task:タスクでフィルタリング
  • tags:配列で指定、タグIDでフィルタリング(例 ?tags=tagId_1&tags=tagId_2)
  • project-required:boolean デフォルト1 – プロジェクト付与の有無
  • task-required:boolean デフォルト1 – タスク付与有無
  • hydrated:boolean project, task, tagsがidでなく、名称含むより詳細な情報を持ったオブジェクトで返される
  • in-progress:boolean 他のすべてのフィルタは無視され、現在実行中のエントリが返される
  • page:デフォルト1 – ページ
  • page-size:デフォルト50 最大5000

今回の取得したいデータの要件は「前日1日のタイムエントリすべてを取得する。ただしエントリ総数は5000は超えないものとする」とします。

この条件に合致するタイムエントリを取得できるように

  • start:開始日時(ISO-8601形式)
  • end:終了日時(ISO-8601形式)
  • page-size:デフォルト50 最大5000

を指定します。

クエリパラメータstartとendはISO-8601形式(タイムゾーン:日本標準時)の文字列

期間指定の開始日時のstartと終了日時のendは当然日時で指定しますが、GASで通常用いるDateオブジェクトでなく、ISO-8601形式で日時を表す文字列で指定します。ISO-8601形式の日時の例が公式ドキュメントに記載がありました。

2019-04-16T05:15:32.998Z

DateオブジェクトをClass UtilitiesformatDate(date, timeZone, format)メソッドを用いることでISO-8601形式の文字列に変換することができます。 仮引数formatには、yyyy-MM-dd’T’HH:mm:ss.SSS’Z’ を指定します。

タイムゾーンの指定に関しては公式ドキュメントに以下の記載があります。

アカウントのタイムゾーンに従って時間を送信します(プロフィール設定参照)

https://clockify.me/developers-api#operation–v1-workspaces–workspaceId–user–userId–time-entries-get

念の為アカウントのプロフィール設定を参照してタイムゾーンを確認します。

UTC +09:00 は日本標準時のことでformatDate(date, timeZone, format)メソッドの仮引数timeZoneに‘JST’を指定します。JSTは、Japan Standard Timeの略ですね。

const now = new Date(); // スクリプト実行時の日時のDateオブジェクト
const today = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0); // 今日の日付 00:00:00を取得
const yesterday = new Date(now.getFullYear(), now.getMonth(), now.getDate() - 1, 0); // 昨日の日付 00:00:00を取得
const startTime = Utilities.formatDate(yesterday, 'JST', "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); // ISO-8601形式の日時にフォーマット タイムゾーンはJST(日本標準時)
const endTime = Utilities.formatDate(today, 'JST', "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); // ISO-8601形式の日時にフォーマット タイムゾーンはJST(日本標準時)

Dateオブジェクトに対して使用できるtoISOString()メソッドでISO-8601形式の文字列を得ることができますが、このメソッドはタイムゾーンがUTCに固定されるため、今回は使用できません。

クエリパラメータを指定して絞り込み

今回の要件である「前日1日のタイムエントリすべてを取得する。ただしエントリ総数は5000は超えないものとする」に合致するクエリパラメータ(絞り込み条件)は以下となります。

  • start:前日の00:00:00
  • end:当日の00:00:00
  • page-size:5000

これをリクエストURLで指定します。

const baseUrl = 'https://api.clockify.me/api/v1'
const dataUrl = `/workspaces/${workspaceId}/user/${userId}/time-entries`;
const paramsUrl = `?start=${startTime}&end=${endTime}&page-size=5000`;
const url = baseUrl + dataUrl + paramsUrl; // 共通URL + 個別URL + クエリパラメータ

このクエリパラメータ(絞り込み条件)を加えたリクエストURLにリクエストを送信したところ、無事絞り込まれたデータを取得できました。

ということで、前日のタイムエントリをすべてログ出力するスクリプト全体は以下の通りになります。

function logYesterdayTimeEntries() {
  const apiKey = PropertiesService.getScriptProperties().getProperty('CLOCKIFY_API_KEY'); // API Keyはプロパティストアに格納
  const workspaceId = PropertiesService.getScriptProperties().getProperty('CLOCKIFY_WORKSPACE_ID'); // Workspace IDはプロパティストアに格納
  const userId = PropertiesService.getScriptProperties().getProperty('CLOCKIFY_USER_ID'); // User IDはプロパティストアに格納

  const now = new Date(); // スクリプト実行時の日時のDateオブジェクト
  const today = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0); // 今日の日付 00:00:00を取得
  const yesterday = new Date(now.getFullYear(), now.getMonth(), now.getDate() - 1, 0); // 昨日の日付 00:00:00を取得
  const startTime = Utilities.formatDate(yesterday, 'JST', "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); // ISO-8601形式の日時にフォーマット タイムゾーンはJST(日本標準時)
  const endTime = Utilities.formatDate(today, 'JST', "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); // ISO-8601形式の日時にフォーマット タイムゾーンはJST(日本標準時)

  const baseUrl = 'https://api.clockify.me/api/v1'
  const dataUrl = `/workspaces/${workspaceId}/user/${userId}/time-entries`;
  const paramsUrl = `?start=${startTime}&end=${endTime}&page-size=5000`;
  const url = baseUrl + dataUrl + paramsUrl; // 共通URL + 個別URL + クエリパラメータ

  /* Class UrlFetchApp のリファレンスからfetch(url, params)メソッドを確認しパラメーターの書き方を読み替える */
  const params = {
    contentType: 'application/json',
    headers: { 'X-Api-Key': apiKey },
    muteHttpExceptions: true // レスポンスが失敗した場合でもエラーを出さずにHTTPResponseを返すオプション
  };

  const response = UrlFetchApp.fetch(url, params); // HTTPResponse
  const json = response.getContentText(); // HTTPResponseの内容の文字列 = JSON文字列
  const aryObj = JSON.parse(json); // JSON文字列をJSONオブジェクトにparse(解析)
  console.log(aryObj.length);
  console.log(aryObj);
}

おわりに

今回のポイントは、APIでリクエストを送信するときのリクエストURLが

  • 共通エンドポイント
  • 個別エンドポイント
  • クエリパラメータ

の組み合わせで作成できる点です。

他のデータ種別でも同様の組み合わせでリクエストURLを作成するので、公式ドキュメントを確認すると良いでしょう。

ということで今回は、前日1日のタイムエントリすべてを取得することができました。

シリーズ目次

  1. タイムトラッカーアプリClockifyのタイムエントリ(時間記録) をAPIでGoogleカレンダーにコピーする その1 – APIの認証を通してサンプルリクエストを送る
  2. タイムトラッカーアプリClockifyのタイムエントリ(時間記録) をAPIでGoogleカレンダーにコピーする その2 – UserとWorkspaceのIDを取得する
  3. タイムトラッカーアプリClockifyのタイムエントリ(時間記録) をAPIでGoogleカレンダーにコピーする その3 – クエリパラメータを指定して前日のエントリのみを取得する
  4. タイムトラッカーアプリClockifyのタイムエントリ(時間記録) をAPIでGoogleカレンダーにコピーする その4 – タイムエントリからカレンダーの予定を作成する

Google Apps Scriptを勉強したい方へ

この記事を見て、GASを勉強したいなと思われた方はぜひノンプログラマーのためのスキルアップ研究会(通称 ノンプロ研)にご参加ください。私も未経験からこの学習コミュニティに参加し、講座を受講したことでGASが書けるようになりました。

学習コミュニティ「ノンプログラマーのためのスキルアップ研究会」

挫折しがちなプログラミングの学習も、コミュニティの力で継続できます。ノンプロ研でお待ちしております!

タグ: , ,
Share on:
Previous Post
カレンダー
GAS活用法

タイムトラッカーアプリClockifyのタイムエントリ(時間記録) をAPIでGoogleカレンダーにコピーする その4 – タイムエントリからカレンダーの予定を作成する

Next Post
Workspace
GAS活用法

タイムトラッカーアプリClockifyのタイムエントリ(時間記録) をAPIでGoogleカレンダーにコピーする その2 – UserとWorkspaceのIDを取得する