PythonでTogglのデータをタイムチャートっぽくExcelに出力
概要
Togglというタイムトラッキングサービスを用いてプライベートな時間の管理をしようと思ったら、タイムチャート的なグラフは見れないみたいなのでPythonでExcelに出せるようにしました。
toggl.com
↓こんなかんじのエクセルが出力されます。
タイムチャートの目盛は15分で、タスクが7分以上だったらプロジェクトの色でその時間帯の目盛に色がつく(被ってたら新しい古いタスクの色で上書き)というふんわりした仕様です。
ソースコード
Python 3.6.3で作成
# -*- coding: <UTF-8> -*- import requests import datetime import calendar import openpyxl as px from openpyxl.styles import PatternFill, Alignment from openpyxl.styles.borders import Border, Side from openpyxl.utils import get_column_letter TARGET_MONTH= "2018-05" #★ここに出力したい月の年月を入力。形式はYYYY-MM #Togglの登録情報から手動で入力する(登録アドレス、ワークスペースID、API Token) MAIL_ADDRESS = "★登録アドレス" WORKSPACE_ID = "★ワークスペースID" API_TOKEN = "★API Token" WEEK = ["月","火","水","木","金","土","日"] #曜日の表記 #listシートとgraphシートの初期表示倍率。お好みで調整 ZOOM_LIST = 60 ZOOM_GRAPH = 90 #時間をdatetime形式に変換する関数 def time_convert(dtz): dt = dtz[0:19] time = datetime.datetime.strptime(dt,"%Y-%m-%dT%H:%M:%S") return time #指定したセルに右縦線を引く関数 def r_border(ws,row,column): ws.cell(row=row,column=column).border = Border( left = Side(style=None), right = Side(style="dashed"), top = Side(style=None), bottom = Side(style=None) ) #ここでエクセルを新規作成 wb = px.Workbook() ws_l = wb.active ws_l.title = "list" ws_g = wb.create_sheet("graph") #TARGET_MONTHの月初の曜日番号&日数を求める t_week, t_days = calendar.monthrange(int(TARGET_MONTH[0:4]),int(TARGET_MONTH[5:7])) #メインループ page = 1 #初期ページ数 p = 1 #今のページ数 while p <= page: #TogglからDetails Reportを取得 PARAMS = { "user_agent": MAIL_ADDRESS, "workspace_id": WORKSPACE_ID, "since":TARGET_MONTH+"-01", "until":TARGET_MONTH+"-"+str(t_days), "page":p, } HEADERS = {"content-type": "application/json"} r = requests.get("https://toggl.com/reports/api/v2/details",auth=(API_TOKEN,"api_token"), headers=HEADERS, params=PARAMS) json_data = r.json() data = json_data["data"] #ページ数の計算。pageが2以上だったら計算済なのでここは飛ばす if page < 2: if json_data["total_count"] <= json_data["per_page"]: page = 1 else: page = int(json_data["total_count"]/json_data["per_page"]) if json_data["total_count"]%json_data["per_page"] != 0: page = page + 1 #タスクの情報を出力 r = json_data["total_count"]-(p-1)*int(json_data["per_page"]) #出力列の開始位置。昇順になるように下から上に出力する for task in data: #listに出力 ws_l.cell(row=r+1,column=1).value = str(time_convert(task["start"])) ws_l.cell(row=r+1,column=2).value = str(time_convert(task["end"])) ws_l.cell(row=r+1,column=3).value = str(time_convert(task["end"])-time_convert(task["start"])) ws_l.cell(row=r+1,column=4).value = task["description"] if task["project_hex_color"] != None: #プロジェクトカラーなしの場合、色塗りつぶししない ws_l.cell(row=r+1,column=5).fill = PatternFill(fill_type="solid", fgColor=task["project_hex_color"][1:7]) ws_l.cell(row=r+1,column=6).value = task["project"] r = r - 1 #graphの描画 if task["project_hex_color"] != None and time_convert(task["end"])-time_convert(task["start"]) >= datetime.timedelta(minutes=7): #終了時間-開始時間が7分以上ならグラフに描画する dur = time_convert(task["end"])-time_convert(task["start"]) c = 0 #横位置調整。終了時間-開始時間が7分以下になるまで右方向に色塗りつぶしを繰り返す ex_r = 0 #縦位置調整。日をまたいだら下の行に移る while dur >= datetime.timedelta(minutes=7): d_column = int(task["start"][11:13])*4+round(int(task["start"][14:16])/15)+c if d_column >= 96: d_column = d_column - 96 ex_r = 1 ws_g.cell(row=int(task["start"][8:10])+ex_r+1,column=d_column+3).fill = PatternFill(fill_type="solid", fgColor=task["project_hex_color"][1:7]) dur = dur - datetime.timedelta(minutes=15) c = c + 1 p = p + 1 #listシートの見栄えを良くする ws_l.cell(row=1,column=1).value = "開始時間" ws_l.cell(row=1,column=2).value = "終了時間" ws_l.cell(row=1,column=3).value = "期間" ws_l.cell(row=1,column=4).value = "タスク名" ws_l.cell(row=1,column=5).value = "色" ws_l.cell(row=1,column=6).value = "PJ名" ws_l.column_dimensions["A"].width = 20 ws_l.column_dimensions["B"].width = 20 ws_l.column_dimensions["C"].width = 8 ws_l.column_dimensions["D"].width = 20 ws_l.column_dimensions["E"].width = 3 ws_l.column_dimensions["F"].width = 20 ws_l.sheet_view.zoomScale = ZOOM_LIST #graphシートの見栄えを良くする ws_g.cell(row=1,column=1).value = "年月日" ws_g.cell(row=1,column=2).value = "曜" for cnt in range(24): #時間軸を横に描画 ws_g.merge_cells(start_row=1,start_column=cnt*4+3,end_row=1,end_column=cnt*4+6) ws_g.cell(row=1,column=cnt*4+3).value = cnt ws_g.cell(row=1,column=cnt*4+3).alignment = Alignment(horizontal="center", vertical="center") w = t_week #日付&曜日を縦に描画 for cnt in range(t_days): ws_g.cell(row=cnt+2,column=1).value = TARGET_MONTH+"-"+"{:0>2}".format(cnt+1) ws_g.cell(row=cnt+2,column=2).value = WEEK[w] w = w + 1 if w > 6: w = 0 for y in range(t_days+1): #罫線を描画。4行目からは列幅の調整など for x in range(25): r_border(ws_g,y+1,x*4+2) ws_g.column_dimensions['A'].width = 13 ws_g.column_dimensions['B'].width = 4 for cnt in range(96): ws_g.column_dimensions[get_column_letter(cnt+3)].width = 1 ws_g.sheet_view.zoomScale = ZOOM_GRAPH wb.save(TARGET_MONTH+"_toggl.xlsx")
【修正履歴】
2018/05/13 プロジェクトカラーなしのタスクがあってもエラーにならないようにした
つかいかた(Pythonさわったことない人向け)
- Togglのウェブサイトにログインして、左下の自分のアイコンから「Profile Settings」画面を開く
- 「Email」と「API Token」を控えておく
- 左のメニューから「Workspaces」画面を開き、情報をゲットしたいワークスペースの「Settings」を開く
- 開いた画面のアドレスバーが「...workspaces/数字/settings?」となっているので、数字の部分(=ワークスペースID)を控えておく
- Python 3.xをインストールする(インストール方法はググってください) Welcome to Python.org
- コマンドプロンプト(macはコマンドライン)で以下の4つのコマンドを入力して必要なモジュールがDLする(pipが使えなかったらググってください) pip requests pip datetime pip calendar pip openpyxl
- 適当なフォルダにメモ帳を新規作成して、↑のソースコードを全て貼り付けて、適当な名前を付けて保存
- ソースコード内の★がついてる4か所に、エクセル出力したい月の対象年月と、つかいかた2、4で控えておいたメールアドレス、API Token、ワークスペースIDを入力する
- メモ帳の拡張子を「.txt」から「.py」に変更
- pyファイルをダブルクリック。黒い画面が出た後、pyファイルと同じ階層に「年月_toggl.xlsx」ファイルが生成されていれば成功
参考にした記事
- GitHub - toggl/toggl_api_docs: Documentation for the Toggl API
- タイム管理アプリTogglの蓄積データをAPI取得し、Pythonで分析する話 - toricago
- Toggl APIとPythonで時間軸一覧レポートの作成に挑戦 - Qiita
- togglのapiをpythonからたたいてみる - Qiita
- [Python] requestsでToggl APIを使ってみる。 | piruty.com
- How to build a pretty Excel timesheet using Toggl API and Python – Random notes from Zena
- メモ:pythonで月末日を取得する方法 (月初日も追記) - Qiita
- Python datetime 日付の計算、文字列から変換【決定版】 - Qiita