勤務時間に応じてその日の賃金を表示するCLIアプリ

# はじめに
暇だったので，その日の勤務時間に応じて今日何円稼いでいるかをリアルタイムで表示するようなCLIアプリを書きました．

バイト中のモチベになるかなと思って作っただけなので，税金などは考慮せず，正確さも適当です．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/609800/bf029923-5483-4104-2c84-2ebb5d6156b4.png)

# アイデア・気づいたこと

- 小さい数字を単位にする方が楽しい

最初は1秒ごとに稼いだ金額を更新していましたが，あまり楽しくない．
1円稼ぐごとに更新しても，時給が十分高ければ楽しいかもしれませんが，バイト程度の賃金だとそこまで楽しくない．

0.01円稼ぐごとに表示し，少数第二位の数字が荒ぶっているくらいが見ていて楽しいです．

- 一日の途中でアプリを起動しても，その時点でその日に稼いだ金額がわかるようにしたほうが良い

PC起動時にアプリも勝手に起動するようにするのを前提として作成しましたが，やはり間違ってウィンドウを閉じてしまったり，PC再起動することはよくあります．
一度起動しても問題ないようにする必要があります．


# コード解説
``` py
import time
import sys
from datetime import datetime
import pyfiglet
```
一週間の勤務時間を書きます．休憩がある場合はその前後で2つ以上に分けて．
``` py
# schedule
timer_schedule = {
    "Monday": [["9:00", "12:00"], ["13:00", "18:00"]],
    "Tuesday": [["9:00", "12:00"], ["13:00", "18:00"]],
    "Wednesday": [["13:00", "18:00"]],
    "Thursday": [],
    "Friday": [],
    "Saturday": [],
    "Sunday": []
}
```
その日，その時点までで稼いだ金額を計算します．
勤務秒数を計算し，それに時給/3600 (秒給) をかけて金額を返します．
``` py
def get_current_count(schedule, current_time, payment):
    total_seconds = 0
    for period in schedule:
        start_time = datetime.strptime(period[0], "%H:%M").time()
        end_time = datetime.strptime(period[1], "%H:%M").time()
        if start_time <= current_time.time() <= end_time:
            total_seconds += (current_time - datetime.combine(current_time.date(), start_time)).seconds
        elif current_time.time() > end_time:
            total_seconds += (datetime.combine(current_time.date(), end_time) - datetime.combine(current_time.date(), start_time)).seconds
    return total_seconds * (payment / 3600)
```
現在時刻が勤務中かどうかを判定する関数．
``` py
def is_within_schedule(schedule, current_time):
    for period in schedule:
        start_time = datetime.strptime(period[0], "%H:%M").time()
        end_time = datetime.strptime(period[1], "%H:%M").time()
        if start_time <= current_time.time() <= end_time:
            return True
    return False
```
main関数．
その時点までの賃金を取得した後，0.01円稼ぐのにかかる秒数を計算．

while文ではアスキーアートのライブラリを使って，0.01円稼ぐごとに数字を更新・表示しています．
勤務時間外はストップです．

``` py
def timer(payment, time_slice):
    current_time = datetime.now()
    weekday = current_time.strftime("%A")
    if weekday in timer_schedule:
        count = get_current_count(timer_schedule[weekday], current_time, payment)
    else:
        count = 0

    interval = time_slice * 3600 / payment # time of 0.01 yen

    try:
        while True:         
            sys.stdout.write("\033[H\033[J")   
            ascii_art = pyfiglet.figlet_format(f"{count:.2f}")
            sys.stdout.write(f"\r{ascii_art}")
            sys.stdout.flush()
            current_time = datetime.now()
            if is_within_schedule(timer_schedule[weekday], current_time):
                time.sleep(interval)
                count += time_slice
            else:
                time.sleep(1) # when its not working time
    except KeyboardInterrupt:
        print("\n timer stopped.")

if __name__ == "__main__":
    payment = 1064 # yen per hour
    time_slice = 0.01 # seconds
    timer(payment, time_slice)
```

# おわりに

ちょっと気を抜いた時にこのタイマーが見えると，ちょっとモチベが上がりますね．……本当に？

ちなみにこのタイマー，0.01円ごとの時間を浮動小数点にしているので精度が悪く，一日が終わるころには500円くらいずれます．
30分おきくらいにget_current_countを使ってリセットを入れると良さそう．