【Python】ひと月分の日報を作成する。


pythonを使用してExcelファイルの操作を勉強しています。
pythonでExcelを操作するため、openpyxlというパッケージを使用しています。

2020年の1月25日からPythonを勉強し始めて2週間ぐらいたったので(適当)
一旦再度の復習もかねて、ひと月分の日報を作ってみたいと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/927441/02f87241-8904-482b-6736-0b4df9a4d0f9.png)
まず、上記のような「原紙」シートを持つブック「日報」を作成します。
実現したい内容は以下です。

1 ひと月分の日報を作る(2021年2月度だったら2月1日～2月28日まで)
2 作成するシートは営業日分だけ(土日祝はお休み。会社休日指定日は勘案しない)。
3 コピーした日報にはD1セルに日付と曜日を入力しておく。
4 コピーした日報のシート名は「△日」と言う表記にする。
5 ブックの名前は「日報_〇月度」と言う表記にする。

# 指定した月の日数を取得
input関数を使って年と月を指定します。
日数を取得するにはcalendar.monthrange()関数を使用すると良いようです。

### calendar.monthrange()関数
月の初日の曜日（月曜は0、日曜は6）と、月の日数のタプルが取得できます。
第一引数に年、第二引数に月を指定します。
今回は日数を取得したいので[1]を後ろにつけます

```python
import calendar

print(calendar.monthrange(2021, 2))
--> (0, 28)

print(calendar.monthrange(2021, 2)[1])
# 28
```

こちらを踏まえて、記述します。

```python:指定した月の日数を取得
year = input('年を半角数字で入力してください。　例「2020」: ')
month = input('月を半角数字で入力して下さい。　例「1」: ')
count = calendar.monthrange(int(year), int(month))[1]
```

# 営業日だけシートを作成する。
日数を取得できたので、for分を使用してシートをコピーしていきたいのですが
休日分も作っていては無駄なので、事前に判定します。
datetimeオブジェクトのweekday()メソッドをしようすると
月曜日は0、日曜日は6の整数値が得られます。

```python
import datetime

dt = datetime.datetime(2021, 2, 1)
print(dt)
# 2021-02-01 00:00:00

print(dt.weekday())
# 0
```

祝日判定はJPHolidayパッケージを使用します。
詳しくはこちらを確認ください。素晴らしいパッケージ！ありがとうございます！

https://github.com/Lalcs/jpholiday

```python
# 指定日が祝日か判定
import jpholiday
import datetime
jpholiday.is_holiday(datetime.date(2017, 1, 1))
> True
```


こちらを使用して、if文を作ります。

```python:土日祝以外はシートをコピー
# 日本語文字列の曜日リストを定義
wb = load_workbook('日報.xlsx')

# 「原紙」のシートを取得
ws_template = wb['原紙']

for i in range(1, int(count) +1):
    # 曜日を取得
    dt = datetime.datetime(int(year), int(month), i)
    holiday = jpholiday.is_holiday(datetime.date(int(year), int(month), i))
    week = dt.weekday()
    # 土日祝を判定
    if week != 5 and week != 6 and holiday == False:
        # シートをコピーする
        ws_copy = wb.copy_worksheet(ws_template)
```

今回は土・日・祝の3日分の判定だったのでこんな記述になりました。
土日祝関係なしの3連勤1日休みだったりしたらどうすればいいのだろう・・・。
考えてみるのも難しそうですが、楽しそうでもありますね！

# 指定したセルに日付と曜日を入力しておく。
こちらは先日勉強したところなのでサクサク進みます。
日付の記載があったセルはD1～G1までがセルが結合されていますが
代表(とでも言うのでしょうか)のD1セルに設定してあげます。

```python:指定したセルに日付と曜日を設定
        # コピーしたシートのセルD1に日付と曜日を設定
        ws_copy['D1'] = f'{month}月  {i}日  {w_list[week]}'
```

今回は日付と曜日だけでしたが社員名とかも同様にちょっこと記述をいじれば出来ちゃいます。

# 日報のシート名は「△日」と言う表記にする。
こちらも以前勉強したところですね。サクサク進めます♪

```python:シート名を「△日」と言う表記にする。
        # シート名を日付にする
        ws_copy.title = f'{i}日'
```

```python:シート名を「〇月△日」と言う表記にする。
        # シート名を日付にする
        ws_copy.title = f'{month}月{i}日'
```
個人的な好みですがシート名が長いのは嫌いなので、今回は日付のみの表記としました。

# ブックの名前は「日報_〇月度」と言う表記にする。
最後に、ブック名を変更して保存します。

```python:ブック名を「日報_〇月度」と言う表記にして保存する
# ブック名を変更して保存
wb.save(f'日報_{month}月度.xlsx')
```

# 出来上がったコード
と言う訳で出来上がったコードがこちらです。

```python:create_report.py
from datetime import date
from openpyxl import load_workbook
import calendar
import datetime
import jpholiday

# 年と月を入力し日数を取得
year = input('年を半角数字で入力してください。　例2020: ')
month = input('月を半角数字で入力して下さい。　例1: ')
count = calendar.monthrange(int(year), int(month))[1]

# 日本語文字列の曜日リストを定義
w_list = ['月曜日', '火曜日', '水曜日', '木曜日', '金曜日', '土曜日', '日曜日']

wb = load_workbook('日報.xlsx')

# 「原紙」のシートを取得
ws_template = wb['原紙']

for i in range(1, int(count) +1):
    # 曜日を取得
    dt = datetime.datetime(int(year), int(month), i)
    holiday = jpholiday.is_holiday(datetime.date(int(year), int(month), i))
    week = dt.weekday()
    # 土・日・祝を判定
    if week != 5 and week != 6 and holiday == False:
        # シートをコピーする
        ws_copy = wb.copy_worksheet(ws_template)
        # コピーしたシートのセルD1に日付と曜日を設定
        ws_copy['D1'] = f'{month}月  {i}日  {w_list[week]}'
        # シート名を日付にする
        ws_copy.title = f'{i}日'

# ブック名を変更して保存
wb.save(f'日報_{month}月度.xlsx')
```

お疲れさまでした。ここまで読んでいただきありがとうございます。
Pythonの勉強を初めてまだ2週間程度ですがなんとか作れました。

まだまだ、したいことも多いので少しづつ勉強を進めて行って
実現できるようになりたいですね！