※当サイトではアフィリエイト広告を利用しています。

自動化

【openpyxl】Excelで日程表を自動的に作る方法

こんにちは、タナカです。

この記事では、openpyxlを使って、エクセルで日程表を作成するコードを紹介します。

突然ですが、皆さんは仕事をするときに日程表を作りますか。

私は製造業で働いているのですが、よく上司に日程表を作って進捗管理をしてくださいと言われます。日程表って項目や対象月が毎回変わるので、前回作った日程表がそのまま使えない場合が多いですよね。

私の場合、日程表を見やすくするために休日(土日)をグレーで色塗りしているのでさらに作るのがめんどくさいです。

ひな形でもいいから日程表の作成を自動化できないかと思い、今回openpyxlを使って自動化プログラムを作りました。

自動的に月や日にちを入力し、休日をグレーで色塗りしてくれるものを作ったのでその内容を紹介したいと思います。

最終的なアウトプットはこのようになっています。

openpyxl-schedule-output
この記事の内容
  • 自動で日程表を作成する方法がわかる
  • 複数セルの操作方法がわかる
  • 自動化プログラムを関数を使って書く

openpyxlの基本的な使い方については【openpyxl】Excelのセル情報を取得する方法を参考にしてください

1. 自動で日程表を作成する方法

今回作成したプログラムはこちらになります。プログラムの中身については、コメントを参照ください。

# openpyxlのインポート
import openpyxl
from openpyxl.styles import Font, PatternFill, Side, Border

# 標準ライブラリのインポート
import calendar
import time

# Excelファイルの読み込み
file_path = r'../data/openpyxl_plan.xlsx'
wb = openpyxl.load_workbook(file_path)

# 対象のシートを指定
ws = wb['Sheet1']

# 値の書き込み
ws.cell(row = 1, column = 1).value = '予定表'

# タイトルの文字サイズを18に変更
ws.cell(row = 1, column = 1).font = Font(size = 18, b = True)

ws.cell(row = 4, column = 2).value = '大項目'
ws.cell(row = 4, column = 3).value = '中項目'
ws.cell(row = 4, column = 4).value = '小項目'

# 罫線を引くための準備
side = Side(style = 'thin', color = '000000')
border = Border(top = side, bottom = side, left = side, right = side)


sat_dict = {} # 土曜日を格納するための辞書{〇月: [x, x+7, x+14..]}
sun_dict = {} # 日曜日を格納するための辞書{〇月: [y, y+7, y+14..]}
last_day_per_month_dict = {} # 月毎の最終日を格納するための辞書{〇月: z, △月: w, ..}

# 8月から12月までを対象にしています
for i in range(8, 12 + 1):
    # 2021年i月のカレンダー情報を取得
    cm = calendar.monthcalendar(2021, i)

    # 休日を取得
    sat_list = [day[5] for day in cm if day[5] != 0]
    sun_list = [day[6] for day in cm if day[6] != 0]

    # 月をキーとして休日を格納
    sat_dict[str(i) + '月'] = sat_list
    sun_dict[str(i) + '月'] = sun_list

    # 月毎の最終日を取得
    last_day = [max(day) for day in cm][-1]

    # 月をキーとして最終日を格納
    last_day_per_month_dict[str(i) + '月'] = last_day

# 開始列の指定
j = 5

# 月毎の情報を取得しエクセルに書き込む
for month in last_day_per_month_dict.keys():
    last_day = last_day_per_month_dict[month]

    for i in range(1, last_day + 1):
        if i == 1:
            ws.cell(row = 3, column = j).value = month

            for t in range(100 + 1):
                ws.cell(row = 3 + t, column = j).border = Border(left = side)

        for saturday in sat_dict[month]:
            if saturday == i:
                for t in range(100):
                    ws.cell(row = 4 + t, column = j).fill = PatternFill(patternType='solid', fgColor = 'CED3DA', bgColor = 'CED3DA')

        for sunday in sun_dict[month]:
            if sunday == i:
                for t in range(100):
                    ws.cell(row = 4 + t, column = j).fill = PatternFill(patternType='solid', fgColor = 'CED3DA', bgColor = 'CED3DA')

        ws.cell(row = 4, column = j).value = i

        # 列の更新
        j += 1


# 罫線の書き込み
for t in range(100 + 1):
    ws.cell(row = 3 + t, column = 1).border = Border(right = side)
    ws.cell(row = 3 + t, column = j).border = Border(left = side)

for k in range(2, j):
    ws.cell(row = 2, column = k).border = Border(bottom = side)
    ws.cell(row = t + 4, column = k).border = Border(top = side)

# ワークブックの保存
wb.save(file_path)

 

今回はその内容を応用して、Excelで日程表を作成するプログラムを作りました。複数セルを扱う方法は、for文などで1つずつセルを取得し順番に処理することで実現できます。

この場合に可変する値はrowやcolumnとなり、それらの値を繰り上げる(+1などする)ことで対象セルを変えています。

2. 自動化プログラムの関数化

上記のような書き方でももちろんいいのですが、もう少し汎用性や作業性を上げるために関数化していきます。

関数で書いたコードは下記になります。

引数にはファイルのパスやシート名、日程表の開始月などを指定できるようにしています。

def createScheduleSheet(file_path,         # ファイルのパス
                        sheet_name,        # シート名
                        start_month,       # 開始月
                        end_month,         # 終了月
                        year,              # 年
                        start_column = 5,  # 日程表を作り始める列
                        last_row = 100):   # 最終行

    # Excelファイルの読み込み
    wb = openpyxl.load_workbook(file_path)

    # 対象のシートを指定
    ws = wb[sheet_name]

    # 値の書き込み
    ws.cell(row = 1, column = 1).value = '予定表'

    # タイトルの文字サイズを18に変更
    ws.cell(row = 1, column = 1).font = Font(size = 18, b = True)

    ws.cell(row = 4, column = 2).value = '大項目'
    ws.cell(row = 4, column = 3).value = '中項目'
    ws.cell(row = 4, column = 4).value = '小項目'

    # 罫線を引くための準備
    side = Side(style = 'thin', color = '000000')
    border = Border(top = side, bottom = side, left = side, right = side)


    sat_dict = {} # 土曜日を格納するための辞書{〇月: [x, x+7, x+14..]}
    sun_dict = {} # 日曜日を格納するための辞書{〇月: [y, y+7, y+14..]}
    last_day_per_month_dict = {} # 月毎の最終日を格納するための辞書{〇月: z, △月: w, ..}

    # 8月から12月までを対象にしています
    for i in range(start_month, end_month + 1):
        # year年i月のカレンダー情報を取得
        cm = calendar.monthcalendar(year, i)

        # 休日を取得
        sat_list = [day[5] for day in cm if day[5] != 0]
        sun_list = [day[6] for day in cm if day[6] != 0]

        # 月をキーとして休日を格納
        sat_dict[str(i) + '月'] = sat_list
        sun_dict[str(i) + '月'] = sun_list

        # 月毎の最終日を取得
        last_day = [max(day) for day in cm][-1]

        # 月をキーとして最終日を格納
        last_day_per_month_dict[str(i) + '月'] = last_day

    # 開始列の指定
    j = start_column

    # 月毎の情報を取得しエクセルに書き込む
    for month in last_day_per_month_dict.keys():
        last_day = last_day_per_month_dict[month]

        for i in range(1, last_day + 1):
            if i == 1:
                ws.cell(row = 3, column = j).value = month

                for t in range(last_row + 1):
                    ws.cell(row = 3 + t, column = j).border = Border(left = side)

            for saturday in sat_dict[month]:
                if saturday == i:
                    for t in range(last_row):
                        ws.cell(row = 4 + t, column = j).fill = PatternFill(patternType='solid', fgColor = 'CED3DA', bgColor = 'CED3DA')

            for sunday in sun_dict[month]:
                if sunday == i:
                    for t in range(last_row):
                        ws.cell(row = 4 + t, column = j).fill = PatternFill(patternType='solid', fgColor = 'CED3DA', bgColor = 'CED3DA')

            ws.cell(row = 4, column = j).value = i

            # 列の更新
            j += 1


    # 罫線の書き込み
    for t in range(last_row + 1):
        ws.cell(row = 3 + t, column = 1).border = Border(right = side)
        ws.cell(row = 3 + t, column = j).border = Border(left = side)

    for k in range(2, j):
        ws.cell(row = 2, column = k).border = Border(bottom = side)
        ws.cell(row = t + 4, column = k).border = Border(top = side)

    # ワークブックの保存
    wb.save(file_path)

 

実際に作成した関数を使ってみます。mainという関数名には特に意味はありません。

def main():
    file_path = r'../data/openpyxl_plan_v2.xlsx'
    sheet_name = 'Sheet1'
    start_month = 4
    end_month = 12
    year = 2021
    start_column = 5
    last_row = 10
    createPlanSheet(file_path, 
                    sheet_name, 
                    start_month, 
                    end_month, 
                    year, 
                    start_column, 
                    last_row)

main()

 

コードを実行した結果がこちらになります。

openpyxl-schedule-output2

他にもGUI化したり、引数に追加できる要素もありますので、ぜひ自分なりにカスタマイズしてみてください。

こういう書き方もあるんだ程度で参考にしていただけると嬉しいです。

まとめ

openpyxlを使ってExcelで日程表を自動的に作るプログラムを作りました。

複数セルを操作する方法は、for文などでrowやcolumnの値を順番に変えることで実現できます。

また、関数にすることで汎用性や作業性を上げることができます。

このプログラムがあれば、めんどうな日程表の作成も楽ができますね。