2021/01/04(月)仕事始め

2021/01/04 21:02

2021年の業務が始まりました。

もうみなさんすっかり忘れてしまっている気もしますが、政府からはもともと1月11日まで休みにして欲しいという呼びかけがありました。弊社は休みにこそしませんでしたが、趣旨を尊重して今週は原則として在宅勤務となっています。ただ、今の状況だと来週以降も在宅勤務は継続ですかね……。

そうなってしまうと、今のiOSプロジェクトはMacを持っている私一人で全部テストする羽目になるので、どうにかならないのか真剣に考えています。ストアに公開するつもりはないけど、アプリを登録してTestFlightでテストアプリを配布するとか?

2021/01/03(日)変わる勇気

2021/01/03 19:49

働きたくないでござる。

西武辻監督コーチ陣に「嫌われろ指令」意識改革促す - プロ野球 : 日刊スポーツ

小関コーチはまだ1年なので評価は保留するとしても、優秀な信号機の黒田、辻監督と戦って陣容を整えつつある西口、豊田以外のコーチは、全員入れ替えの候補になってしかるべきだと思っています。老後のレクリエーションではないのですから、みなさんそろそろ真剣にやっていただきたい。

また、辻監督自身にも変わる勇気を持っていただいて、甘く野球をやっている32歳にそろそろ見切りをつけていただきたいと思います。

2021/01/02(土)書き初め

2021/01/02 20:36

2021年最初のプログラムを書きました。100行にも満たないプログラムですが、仕事でやっている言語を離れて好きな言語を使える喜びに満ちた、とても楽しい時間を過ごすことができました。

私は作業時間のトラッキングにToggl Trackを利用しており、各エントリのClientにその時間が消費、投資、浪費のどれに当たるかを指定しています。より厳密には、消費、投資、浪費にぶら下げる形で各Projectを作り、それをエントリに割り当てています。

今日作成したのは、一日の時間の使い方を集計するプログラムです。入力が20210101であれば、2021年1月1日の0時から2日の0時までの24時間を対象に、Clientごとの合計時間を集計します。日をまたいだエントリについては、前日分、翌日分を破棄し、当日24時間の中に入っている部分のみを集計します。

もともとAPIの戻り値にはdurationという作業時間の項目があるのですが、今回は当該エントリの開始時刻から次のエントリの開始時刻までを作業時間としています。アプリの操作やサーバー同期の都合上、どうしても終了→即座に次のエントリ開始というわけには行かず、数秒の空白の時間帯が発生してしまうからです。

from itertools import groupby
from datetime import datetime, timedelta, timezone
from functools import cache
import sys
import time
import requests

API_TOKEN = '<YOUR_API_TOKEN>'
END_POINT = 'https://api.track.toggl.com/api/v8/'
WAIT = 1

def main(target):
    target_date = datetime.strptime(target, '%Y%m%d').replace(tzinfo=timezone(timedelta(hours=9), 'JST'))
    start_date = target_date + timedelta(days=-1)
    end_date = target_date + timedelta(days=1)

    params = {
        "start_date": start_date.isoformat(timespec='seconds'),
        "end_date": end_date.isoformat(timespec='seconds'),
    }
    response = requests.get(END_POINT + 'time_entries', params, auth=(API_TOKEN, 'api_token')).json()

    entries = list(map(
        lambda x: {
            'pid': x['pid'],
            'start': max(datetime.fromisoformat(x['start']), target_date),
        },
        filter(lambda x: datetime.fromisoformat(x['stop']) > target_date, response)
    ))

    durations = [(
        fetch_project(start['pid'])[0],
        stop['start'] - start['start']
    ) for start, stop in zip(entries, entries[1:] + [{'pid': 0, 'start': end_date}])]

    result = [(
        k,
        sum([duration[1] for duration in v], timedelta())
    ) for k, v in groupby(sorted(durations, key=lambda x: x[0]), lambda y: y[0])]

    for k, v in result:
        print(k, format_timedelta(v))

@cache
def fetch_project(pid):
    time.sleep(WAIT)
    response = requests.get(END_POINT + 'projects/' + str(pid), auth=(API_TOKEN, 'api_token')).json()
    return fetch_client(response['data']['cid']), response['data']['name']

@cache
def fetch_client(cid):
    time.sleep(WAIT)
    response = requests.get(END_POINT + 'clients/' + str(cid), auth=(API_TOKEN, 'api_token')).json()
    return response['data']['name']

def format_timedelta(td):
    hours, remainder = divmod(td.seconds, 3600)
    minutes, seconds = divmod(remainder, 60)
    return f"{hours:02}:{minutes:02}:{seconds:02}"

if __name__ == '__main__':
    main(sys.argv[1])

2021/01/01(金)謹賀新年

2021/01/01 21:09

あけましておめでとうございます。本年もよろしくお願いいたします。

2004年から書き始めたこのブログも、何度かの移転を経て足掛け18年目に突入しました。最近はチラシの裏のようなエントリが増えていますが、そもそもこのサイトはブログというより古き良き時代のWeb日記の親戚だと思っています。今後も私の興味のおもむくまま、埼玉西武ライオンズやクイズマジックアカデミーやPythonについて熱く語ったり語らなかったりする予定です。

このサイトをご覧のみなさまにとって、2021年が良い年となりますように。