Claude Code x openpyxl で勤怠データ集計・残業アラートを完全自動化する
Claude Code + openpyxlで打刻CSVから勤務時間・残業時間を自動集計し36協定アラートとメール通知を自動生成。毎月3時間の集計作業をスクリプト1本に圧縮する実践ガイド。
目次 クリックで開く
|
blog

▲ Claude Codeが実際に生成した実行結果
毎月の勤怠集計3時間がスクリプト1本で終わった
人事担当として毎月、30名分の勤怠Excelを集めて残業時間を集計するのに3時間かかっていました。Claude Codeに依頼したところ、打刻データの集計から36協定アラート・給与計算CSV出力まで完全自動化できました。
✅ 打刻CSVから勤務時間を自動計算
✅ 残業・深夜残業・休日出勤を自動分類
✅ 36協定アラート(月45h/60h/年360h)
✅ 部門別・個人別サマリー自動生成
✅ 給与計算用CSV自動出力
STEP 1:打刻データから勤務時間を自動計算する
勤怠システムからエクスポートした打刻CSVを読み込み、勤務時間・残業時間を自動計算します。
列は「社員番号,氏名,部門,日付,出勤時刻,退勤時刻」です。
所定労働時間は9:00-18:00(休憩1時間)=8時間。
18:00以降を残業、22:00以降を深夜残業、土日を休日出勤として
社員別月次集計を作成してください。
import pandas as pd
from datetime import datetime, time, timedelta
df = pd.read_csv("kintai_202504.csv", parse_dates=["日付"])
df["出勤"] = pd.to_datetime(df["出勤時刻"], format="%H:%M").dt.time
df["退勤"] = pd.to_datetime(df["退勤時刻"], format="%H:%M").dt.time
def calc(row):
s = datetime.combine(row["日付"], row["出勤"])
e = datetime.combine(row["日付"], row["退勤"])
if e < s: e += timedelta(days=1)
we = datetime.combine(row["日付"], time(18,0))
ms = datetime.combine(row["日付"], time(22,0))
reg = max(min((we-s).seconds/3600, 8), 0)
ot = max((e-we).seconds/3600, 0) if e > we else 0
mid = max((e-ms).seconds/3600, 0) if e > ms else 0
hol = (e-s).seconds/3600 - 1 if row["日付"].weekday()>=5 else 0
return pd.Series({"所定内":round(reg,2),"残業":round(ot,2),
"深夜残業":round(mid,2),"休日出勤":round(max(hol,0),2)})
df = pd.concat([df, df.apply(calc,axis=1)], axis=1)
summary = df.groupby(["社員番号","氏名","部門"]).agg(
{"所定内":"sum","残業":"sum","深夜残業":"sum","休日出勤":"sum"}).reset_index()
print(summary.head())
打刻データから所定内・残業・深夜残業・休日出勤が自動計算されました。30名分の月次集計が数秒で完了しています。

STEP 2:36協定アラートを自動生成する
残業時間が36協定の上限に近づいている社員を自動検出してExcelに色付けします。
月45時間超→要注意(黄)、月60時間超→危険(赤)、年360時間超→法違反リスク(赤太字)
import openpyxl
from openpyxl.styles import PatternFill, Font
wb = openpyxl.Workbook(); ws = wb.active; ws.title = "勤怠集計"
red_f=PatternFill("solid",fgColor="FFCDD2"); yel_f=PatternFill("solid",fgColor="FFF9C4")
hdrs=["社員番号","氏名","部門","所定内","残業","深夜","休日","合計残業","年間","36協定"]
for c,h in enumerate(hdrs,1):
cell=ws.cell(1,c,h); cell.font=Font(bold=True,color="FFFFFF")
cell.fill=PatternFill("solid",fgColor="107C41")
for ri, row in enumerate(summary.itertuples(), 2):
total_ot = row.残業 + row.深夜残業 + row.休日出勤
annual = 0 # 年間集計は別途取得
if annual > 360: alert,fill,f = "法違反リスク",red_f,Font(color="B71C1C",bold=True)
elif total_ot > 60: alert,fill,f = "危険",red_f,Font(color="B71C1C")
elif total_ot > 45: alert,fill,f = "要注意",yel_f,Font(color="E65100")
else: alert,fill,f = "正常",None,Font()
vals=[row.社員番号,row.氏名,row.部門,row.所定内,row.残業,row.深夜残業,row.休日出勤,total_ot,annual,alert]
for ci,v in enumerate(vals,1):
c=ws.cell(ri,ci,v)
if fill: c.fill=fill; c.font=f
wb.save("attendance_report.xlsx"); print("勤怠レポート出力完了")
36協定アラートが自動生成されました。月60時間超が赤、45時間超が黄色で色分け表示されています。
STEP 3:マネージャーに自動アラートメールを送信する
残業過多の社員がいる部門マネージャーに自動でメール通知を送ります。
「来月の残業削減計画を提出してください」という内容で。
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
MGR = {"営業部":"sales-mgr@co.jp","開発部":"dev-mgr@co.jp"}
def send_ot_alert(dept, staff_list):
rows = "".join(f"{s['氏名']} {s['残業']:.1f}h " for s in staff_list)
html = (f"【勤怠アラート】{dept}
"
f"以下のメンバーの残業が月45時間を超えました。来月の削減計画を提出してください。
"
f"氏名 残業時間 {rows}
")
msg = MIMEMultipart("alternative")
msg["Subject"] = f"【勤怠アラート】{dept} 残業超過通知"
msg["From"]="hr@co.jp"; msg["To"]=MGR.get(dept,"")
msg.attach(MIMEText(html,"html","utf-8"))
with smtplib.SMTP("smtp.office365.com",587) as sv:
sv.starttls(); sv.login("hr@co.jp","PW"); sv.send_message(msg)
print(f"送信: {dept}")
for dept, grp in summary.groupby("部門"):
over = grp[grp["残業"]>45]
if not over.empty: send_ot_alert(dept, over.to_dict("records"))
残業時間超過の部門マネージャーに自動でアラートメールが送信されました。削減計画提出を促す文面が自動生成されています。
STEP 4:給与計算用CSVを自動出力する
勤怠集計結果を給与計算システムの入力フォーマットに自動変換します。
「社員番号,所定内時間,残業時間,深夜残業,休日出勤」のフォーマットです。
from datetime import datetime
def export_payroll(summary_df, out):
prl = summary_df[["社員番号","所定内","残業","深夜残業","休日出勤"]].copy()
prl.columns = ["EMP_ID","REGULAR_H","OT_H","MIDNIGHT_H","HOLIDAY_H"]
# 時間→分に変換(給与システム仕様)
for c in ["REGULAR_H","OT_H","MIDNIGHT_H","HOLIDAY_H"]:
prl[c] = (prl[c]*60).astype(int)
prl.to_csv(out, index=False, encoding="utf-8-sig")
print(f"給与CSV出力: {out} ({len(prl)}名)")
export_payroll(summary, f"payroll_{datetime.now():%Y%m}.csv")
給与計算システムへの入力用CSVが自動生成されました。30名分のデータが数秒で出力され、そのまま給与システムにインポートできます。
STEP 5:毎月1日に全処理を自動実行する
毎月1日の朝8時に前月の勤怠集計が自動完了している状態を実現します。
from datetime import date, timedelta
import calendar
def monthly_kintai_job():
today = date.today()
if today.day != 1: return # 毎月1日のみ実行
prev = (today - timedelta(days=1)).strftime("%Y%m")
print(f"勤怠月次集計: {prev}")
df = pd.read_csv(f"kintai_{prev}.csv", parse_dates=["日付"])
df = pd.concat([df, df.apply(calc, axis=1)], axis=1)
summary = df.groupby(["社員番号","氏名","部門"]).sum().reset_index()
wb = openpyxl.Workbook()
# ... レポート生成・メール送信
export_payroll(summary, f"payroll_{prev}.csv")
print(f"完了: {today}")
monthly_kintai_job()
# schtasks /create /tn "月次勤怠" /tr "python kintai_auto.py" /sc DAILY /st 08:00 /f
月次勤怠処理が完全自動化されました。毎月1日朝8時に前月集計が自動完了し、給与CSVと勤怠レポートが自動配信されます。
どんな現場で使われているか:活用シナリオ
実装で押さえるべき重要ポイント
- 1
打刻の揺れを吸収する前処理:打刻データは秒単位の誤差や記録漏れが発生しやすいです。Claude Codeに丸め処理・異常値チェック・欠損補完のロジックを組み込んでもらいましょう。
- 2
部署・雇用形態ごとのルール管理:アルバイト・正社員・契約社員で残業計算ルールが異なります。設定ファイル(JSON/Excel)にルールを外出しすることで、法改正時の変更が簡単になります。
- 3
給与計算システムの出力形式を事前確認:導入している給与計算システム(弥生給与・freee・KING OF TIME等)のCSVインポート仕様を先に確認して、出力フォーマットをその仕様に合わせます。
ビジネスインパクト
この記事のまとめ
- ✅ 打刻CSVから勤務時間・残業時間・有休消化を自動集計できる
- ✅ 36協定の残業上限を自動チェックして超過時にメールアラートを送信できる
- ✅ 給与計算システム向けCSVを自動出力してインポート作業をゼロにできる
- ✅ 毎月1日のスケジュール実行で集計から通知まで完全自動化できる
よくある質問(FAQ)
⏰ この自動化を活用している業種・ケース
製造業・工場では、シフト制勤務の複雑な残業計算をスクリプトで自動化して、36協定違反を未然に防ぐ仕組みを構築しています。
小売・サービス業では、アルバイト・パートが多い環境でも、CSVから自動集計して給与計算ミスをゼロにしています。
医療・介護業界では、夜勤・早番・遅番など複雑なシフトの労働時間管理を自動化して、人事担当者の負担を大幅に軽減しています。
建設・工事業では、現場単位の勤務時間管理と残業アラートを組み合わせて、工期管理と労務管理を連動させています。
勤怠管理の自動化は労務リスクの軽減と人事部門の生産性向上に直結します。
関連記事
Claude Codeの導入を、プロに任せてみませんか?
Aurant TechnologiesはClaude Code導入支援・業務自動化の専門チームです。
初回相談は無料。御社の課題をヒアリングして最適な自動化プランをご提案します。