ics形式のカレンダー情報を使って勤務時間を集計することにした

# はじめに

システム開発のコストを算出するために、労働時間を作業内容別に管理しなくてはならず、どうやってそれを実現するか考えてみたところ、カレンダーアプリに登録したスケジュールをics形式のファイルで取得して時間を集計するスクリプトを作ってみました。

# スケジュールの登録

作業内容別に名称を統一してカレンダーに登録します。

# icsファイルの取得

icsファイルをダウンロード・保存できるサービスやアプリを利用してicsファイルを取得します。

- [Googleカレンダー](https://support.google.com/calendar/answer/37111?hl=ja)
- Mac標準カレンダー
- Windows版Outlook
- [Yahoo!カレンダー](https://calendar.yahoo.co.jp/info/guide/sync.html)
- [サイボウズ ガルーン](https://manual.cybozu.co.jp/gr35help/ja/g/user/schedule/setting.html)

直接はicsファイルを取得できないアプリの場合、GoogleカレンダーやMac標準カレンダーなどと連携してこれらのアプリから取得することもできます。

- Outlook  
[Mac で Office365 Outlookのスケジュールを Calendar に同期する
](https://qiita.com/furu8ma/items/a24c863925fb89fe5aeb)

# 読込と時間計算

以下のスクリプトを実行。
ここでは、取得したファイルを「作業時間.ics」として保存します。

```py:read_ics.py
# -*- coding: utf-8

import pandas as pd

file = "作業時間.ics"

# ファイル読込
with open(file) as f:
    lines = f.readlines()

events = []

flg = False

dtstart = ""
dtend = ""
summary = ""

for l in lines:
    
    l = l.strip()
    
    # スケジュール開始を確認
    if l.find("BEGIN:VEVENT") > -1:
        flg = True
        
    if flg:
        
        # 開始時間を取得
        if l.find('DTSTART') > -1:
            dtstart = pd.to_datetime(l.split(":")[-1])

        # 終了時間を取得
        if l.find('DTEND') > -1:
            dtend = pd.to_datetime(l.split(":")[-1])

        # スケジュール内容を取得
        if l.find('SUMMARY') > -1:
            summary = l.split(":")[-1]
            
        # スケジュール終了を確認
        if l.find("END:VEVENT") > -1:
            flg = False
            events.append([dtstart, dtend, dtend - dtstart, summary])

# データフレーム化
df = pd.DataFrame(events, columns=["dtstart","dtend","hours","summary"])
df.index = df.dtstart

# 集計用データフレームの作成
df_sum = df["2018-12-01":"2018-12-31"]

# 内容別の時間集計
for s in df_sum.summary.value_counts().index:
    
    t = df_sum[df_sum.summary == s].hours.sum()
    hours = t.delta / (10**9 * 60 * 60)
    
    print("{} {}[h]".format(s, hours))
```

実行すると...

```sh:
$ python read_ics.py

学習モデル開発 67.0[h]
管理システム開発 32.0[h]
資料作成ほか 25.0[h]
```

できた！

# Googleカレンダーから直接取得する

上記のコードを変更し、Googleカレンダーから直接取得する方法に変更します。
取得するicsファイルのURLは各カレンダーの設定から確認して下さい。

```py:read_url.py
# -*- coding: utf-8
import urllib.request
import pandas as pd

url = "https://calendar.google.com/calendar/ical/[xxxx]/basic.ics"

with urllib.request.urlopen(url) as f:
    lines = f.readlines()

events = []

flg = False

dtstart = ""
dtend = ""
summary = ""

for l in lines:
    
    l = l.strip()
    
    # スケジュール開始を確認
    if l.find("BEGIN:VEVENT") > -1:
        flg = True
        
    if flg:
        
        # 開始時間を取得
        if l.find('DTSTART') > -1:
            dtstart = pd.to_datetime(l.split(":")[-1])

        # 終了時間を取得
        if l.find('DTEND') > -1:
            dtend = pd.to_datetime(l.split(":")[-1])

        # スケジュール内容を取得
        if l.find('SUMMARY') > -1:
            summary = l.split(":")[-1]
            
        # スケジュール終了を確認
        if l.find("END:VEVENT") > -1:
            flg = False
            events.append([dtstart, dtend, dtend - dtstart, summary])

# データフレーム化
df = pd.DataFrame(events, columns=["dtstart","dtend","hours","summary"])
df.index = df.dtstart

# 集計用データフレームの作成
df_sum = df["2018-12-01":"2018-12-31"]

# 内容別の時間集計
for s in df_sum.summary.value_counts().index:
    
    t = df_sum[df_sum.summary == s].hours.sum()
    hours = t.delta / (10**9 * 60 * 60)
    
    print("{} {}[h]".format(s, hours))
```

できた！

URLを変更すればGooleカレンダー以外のサービスでも同じことができるに違いない！