うろん

なんかいろいろ書きます

PythonでTogglのデータをタイムチャートっぽくExcelに出力

概要

Togglというタイムトラッキングサービスを用いてプライベートな時間の管理をしようと思ったら、タイムチャート的なグラフは見れないみたいなのでPythonExcelに出せるようにしました。
toggl.com

↓こんなかんじのエクセルが出力されます。
タイムチャートの目盛は15分で、タスクが7分以上だったらプロジェクトの色でその時間帯の目盛に色がつく(被ってたら新しい古いタスクの色で上書き)というふんわりした仕様です。
f:id:giccyon:20180506005616j:plain:h200 f:id:giccyon:20180506005605j:plain:h200

ソースコード

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さわったことない人向け)

  1. Togglのウェブサイトにログインして、左下の自分のアイコンから「Profile Settings」画面を開く
  2. 「Email」と「API Token」を控えておく
  3. 左のメニューから「Workspaces」画面を開き、情報をゲットしたいワークスペースの「Settings」を開く
  4. 開いた画面のアドレスバーが「...workspaces/数字/settings?」となっているので、数字の部分(=ワークスペースID)を控えておく
  5. Python 3.xをインストールする(インストール方法はググってください)
  6. Welcome to Python.org
  7. コマンドプロンプトmacコマンドライン)で以下の4つのコマンドを入力して必要なモジュールがDLする(pipが使えなかったらググってください)
  8.  pip requests  pip datetime  pip calendar  pip openpyxl
  9. 適当なフォルダにメモ帳を新規作成して、↑のソースコードを全て貼り付けて、適当な名前を付けて保存
  10. ソースコード内の★がついてる4か所に、エクセル出力したい月の対象年月と、つかいかた2、4で控えておいたメールアドレス、API Token、ワークスペースIDを入力する
  11. メモ帳の拡張子を「.txt」から「.py」に変更
  12. pyファイルをダブルクリック。黒い画面が出た後、pyファイルと同じ階層に「年月_toggl.xlsx」ファイルが生成されていれば成功