Claudeで看護の勤務表と夜勤72時間を点検する — コード実行で月平均を検算
病棟の勤務表CSVから職員ごとの夜勤時間と月平均を出し、72時間以下の基準・除外ルール・連続夜勤・勤務間隔を点検する手順です。計算はClaudeのコード実行に任せ、手元のPythonで検算します。
Claudeで看護の勤務表と夜勤72時間を点検する — コード実行で月平均を検算
病棟の勤務表から月平均の夜勤時間数を出すとき、手が止まりやすいのは足し算ではなく数え方です。夜勤時間帯と重なった分だけを数え、夜勤専従者と夜勤が短い職員を平均から外し、日付をまたぐ勤務を正しく切る必要があります。この計算をClaudeの暗算に任せず、コード実行ツールで集計し、手元のPythonで検算する手順を示します。
勤務表のデータは架空の病棟(8名・2026年11月)です。基準の数値は、令和8年3月5日付の厚生労働省通知(保医発0305第7号)から引いています。
点検の物差しは「月平均72時間以下」と除外ルール
この通知では、一般病棟・結核病棟・精神病棟・障害者施設等の入院基本料の基準として、夜勤を行う看護職員1人当たりの月平均の夜勤時間数が72時間以下であることが示されています。点検の前に、数え方の決まりを4点押さえておきます。
月平均の夜勤時間数を決める4つの決まり
夜勤時間帯
午後10時から翌午前5時を含む連続16時間を、医療機関が自分で定めます。この枠と重なった勤務時間だけが夜勤時間です。
平均から外す人
夜勤専従者は人数にも時間にも入れません。急性期一般の入院基本料や7対1・10対1では月16時間未満の人も外し、短時間正職員は月12時間以上なら含めます。
それ以外の入院基本料
月8時間未満の人を平均から外します。16時間と8時間は入院基本料の区分で切り替わります。
計算の単位
同じ入院基本料を算定する病棟全体で、届出前1か月または4週間の延べ夜勤時間を実人員で割ります。病棟ごとに72時間以下である必要はありません。
申し送りの扱いにも決まりがあります。夜勤時間帯の中で申し送りに要した時間は、申し送った職員の夜勤時間から除いて差し支えありません。除外するかどうかは、原則として同じ入院基本料の病棟全体で月単位に選びます。
基準を満たせなくなった場合の扱いも通知にあります。月平均の夜勤時間数の基準だけを満たせないときは、満たせなくなってから直近3月に限って、月平均夜勤時間の超過減算による入院基本料で算定できます。さらに、この要件だけを満たせない病棟向けに夜勤時間を理由とする特別な区分があり、算定には医療の勤務環境改善を支援するセンターへの相談などが条件です。
夜勤時間は「枠と重なった時間」で数える
勤務表の「準夜」「深夜」という名前から、1回の夜勤を一律8時間と置くと、ずれます。通知は夜勤を、夜勤時間帯の間に現に勤務することと定めているからです。日勤が枠にかかる、深夜が枠の外に出る、といった端数は、重なりを計算して初めて出ます。
このあとの例は、次の設定で組みました。
| 勤務 | 時間 | 夜勤時間として数える分 |
|---|---|---|
| 日勤 | 時間8:30〜16:30 | 夜勤時間として数える分0時間 |
| 準夜 | 時間16:30〜翌1:00 | 夜勤時間として数える分8.5時間 |
| 深夜 | 時間0:30〜8:30 | 夜勤時間として数える分8時間 |
夜勤時間帯は16:30〜翌8:30の16時間です。準夜の終わりと深夜の始まりは30分重なり、この30分が申し送りに当たります。時刻や枠は病院ごとに違うため、自院の設定に置き換えてください。
勤務表CSVをコード実行ツールに渡す
勤務表は1行1勤務の縦持ちCSVにします。列は職員、区分(交代制か夜勤専従)、日付、勤務の4つです。職員欄は氏名ではなく「看護師A」のような仮名か職員番号にします。
staff,kind,date,shift
看護師A,交代制,2026-11-01,日
看護師A,交代制,2026-11-02,準
看護師A,交代制,2026-11-03,休コード実行ツールにはCSVをアップロードして渡せます。Files APIでアップロードし、リクエストの container_upload ブロックで参照し、ツール定義に code_execution を加えます。ツール定義の code_execution_20250825 は、Bashとファイル操作が使える版です。
import anthropic
from pathlib import Path
client = anthropic.Anthropic()
f = client.files.upload(file=Path("roster.csv"))
prompt = """添付の勤務表CSVを点検してください。計算は必ずコード実行で行います。
規則:
- 夜勤時間帯は16:30から翌8:30の16時間
- 日勤8:30-16:30、準夜16:30-翌1:00、深夜0:30-8:30
- 夜勤時間は、各勤務と夜勤時間帯が重なった時間
- 区分が夜勤専従の人と、月の夜勤時間が16時間未満の人は、
人数にも延べ時間にも入れない
- 月平均の夜勤時間数 = 延べ夜勤時間 / 夜勤従事者数
- 夜勤が連続する暦日数と、勤務終了から次の勤務開始までの
間隔が11時間未満の回数も、職員ごとに出す
職員ごとの表と月平均を示し、実行したコードを添えてください。"""
resp = client.messages.create(
model="claude-opus-5-5",
max_tokens=4096,
messages=[{"role": "user", "content": [
{"type": "text", "text": prompt},
{"type": "container_upload", "file_id": f.id},
]}],
tools=[{"type": "code_execution_20250825", "name": "code_execution"}],
)
print(resp.to_json())規則をプロンプトに書くのは、数値をClaudeの記憶に頼らないためです。通知は改定のたびに変わるので、手元の最新の通知から数値を写して渡します。
渡す前に確認したい条件が3つあります。
- 公式ページでは、この機能はゼロデータ保持(ZDR)の対象外と示されています
- コンテナ内のデータ(アップロードしたファイルや出力を含む)は最大30日間保持されます
- ファイルを付けたリクエストは、ツールを呼ばなくても実行時間が課金されます
職員の勤務実績は個人に紐づく情報です。氏名を仮名にし、自院の情報管理の規程で外部サービスに渡せるデータかを先に確かめます。料金はコード実行ツールが無料になる条件で整理しています。
手元のスクリプトで同じ計算を回す
Claudeが返した表だけで終わらせず、同じ規則を実装したスクリプトに同じCSVを通します。2つの数字が一致して初めて、規則の解釈と日付計算の両方が合ったと言えます。
import csv, sys
from collections import defaultdict
from datetime import datetime, timedelta
SHIFTS = { # 勤務 -> (開始, 終了) 終了が開始より前なら翌日
"日": ("08:30", "16:30"),
"準": ("16:30", "01:00"),
"深": ("00:30", "08:30"),
}
WIN_START, WIN_HOURS = "16:30", 16 # 夜勤時間帯 16:30-翌08:30(16時間)
MIN_HOURS, MAX_AVG = 16, 72 # 月16時間未満は除外 / 月平均72時間以下
HANDOVER = {"準": 0.5} # 申し送り(時間)。除外する運用のときだけ使う
def span(day, key):
s, e = SHIFTS[key]
d = datetime.strptime(day, "%Y-%m-%d")
st = datetime.combine(d, datetime.strptime(s, "%H:%M").time())
en = datetime.combine(d, datetime.strptime(e, "%H:%M").time())
return st, en + timedelta(days=1) if en <= st else en
def overlap(a, b, c, d):
return max(timedelta(0), min(b, d) - max(a, c)).total_seconds() / 3600
def night_hours(day, key, exclude_handover):
st, en = span(day, key)
h = 0.0
for off in (-1, 0, 1): # 暦日をまたぐので前日・当日・翌日の窓を見る
w0 = datetime.strptime(day, "%Y-%m-%d") + timedelta(days=off)
w0 = w0.replace(hour=int(WIN_START[:2]), minute=int(WIN_START[3:]))
h += overlap(st, en, w0, w0 + timedelta(hours=WIN_HOURS))
if exclude_handover:
h -= HANDOVER.get(key, 0)
return h
def main(path, exclude_handover=False):
staff = defaultdict(list); kind = {}
for r in csv.DictReader(open(path, encoding="utf-8")):
kind[r["staff"]] = r["kind"]
if r["shift"] in SHIFTS:
staff[r["staff"]].append((r["date"], r["shift"]))
total = people = 0; naive_t = naive_p = 0
print(f"{'職員':<7}{'区分':<8}{'夜勤時間':>8} 対象 メモ")
for s in sorted(kind):
recs = sorted(staff[s], key=lambda x: span(*x)[0])
h = sum(night_hours(d, k, exclude_handover) for d, k in recs)
# 平均の計算対象か
counted = kind[s] != "夜勤専従" and h >= MIN_HOURS
notes = []
# 勤務間隔(前の勤務の終了から次の開始まで)
short = []
for (d0, k0), (d1, k1) in zip(recs, recs[1:]):
gap = (span(d1, k1)[0] - span(d0, k0)[1]).total_seconds() / 3600
if gap < 11:
short.append(d1[5:])
# 連続夜勤(夜勤を含む勤務が連続する暦日の数)
nd = sorted({datetime.strptime(d, "%Y-%m-%d") for d, k in recs if night_hours(d, k, False) > 0})
best = run = 0; last = None
for d in nd:
run = run + 1 if last and (d - last).days == 1 else 1
best = max(best, run); last = d
if short: notes.append(f"間隔11h未満{len(short)}回")
if best >= 3: notes.append(f"夜勤{best}連続")
if not counted: notes.append("平均から除外")
print(f"{s:<7}{kind[s]:<8}{h:>8.1f} {'○' if counted else '-':^4} {' '.join(notes)}")
if counted: total += h; people += 1
if kind[s] != "夜勤専従": naive_t += h; naive_p += 1
avg = total / people
print(f"\n月延べ夜勤時間 {total:.1f} / 夜勤従事者 {people} 人 = 月平均 {avg:.1f} 時間 ({'基準内' if avg <= MAX_AVG else '72時間超'})")
print(f"(参考)16時間未満の職員も含めた場合: {naive_t/naive_p:.1f} 時間")
main(sys.argv[1], "--handover" in sys.argv)実行は次のとおりです。--handover を付けると、準夜から申し送りの30分を引きます。
python3 check.py roster.csv
python3 check.py roster.csv --handoverPython 3.12.2で実行した出力が次です(1回目は申し送りを引かない場合)。
職員 区分 夜勤時間 対象 メモ
看護師A 交代制 74.5 ○ 間隔11h未満5回
看護師B 交代制 82.5 ○ 間隔11h未満3回
看護師C 交代制 82.5 ○ 間隔11h未満6回
看護師D 交代制 72.0 ○ 間隔11h未満2回 夜勤3連続
看護師E 交代制 74.5 ○ 間隔11h未満4回
看護師F 交代制 66.5 ○ 間隔11h未満3回
看護師G 交代制 8.0 - 間隔11h未満1回 平均から除外
看護師H 夜勤専従 127.5 - 平均から除外
月延べ夜勤時間 452.5 / 夜勤従事者 6 人 = 月平均 75.4 時間 (72時間超)
(参考)16時間未満の職員も含めた場合: 65.8 時間--handover を付けた2回目の末尾は次のとおりです。
月延べ夜勤時間 440.0 / 夜勤従事者 6 人 = 月平均 73.3 時間 (72時間超)
(参考)16時間未満の職員も含めた場合: 64.0 時間結果の読み方は除外ルールで変わる
この病棟の月平均は75.4時間で、72時間を超えています。ここで効いているのは除外ルールです。
16時間未満の看護師G(8時間)を人数に入れると、平均は65.8時間に下がり、基準内に見えます。夜勤専従の看護師Hを外し忘れると、逆に上へ振れます。除外の判定を暗算やExcelの目分量に任せると、結論そのものが反転します。
申し送りの扱いでも数字は動きます。準夜の30分を引くと73.3時間まで下がりますが、この例では基準を超えたままです。申し送りを除くかどうかは月単位で全体に揃える決まりのため、職員ごとに使い分けられません。
落とし穴
平均を下げるために少ない夜勤の人を足してはいけません
月16時間未満の職員は、平均の計算から外れる決まりです。人数に入れて平均を下げても、届出の計算とは一致しません。点検では、除外される側の人数と時間を別に表示し、平均に入った人数と合わせて確かめます。
連続夜勤と勤務間隔を並べて見る
月平均が72時間以下でも、勤務の組み方に偏りがあれば別の基準に触れます。通知は、夜間看護体制の評価で次の項目を示しています(障害者施設等の入院基本料の夜間看護体制の加算では、ア・ウを含む4項目以上など)。
- 勤務終了時刻と直後の勤務開始時刻の間が11時間以上であること
- 連続して行う夜勤の数が2回以下であること
- 3交代制の病棟では、勤務開始時刻が直近の勤務の開始時刻の概ね24時間後以降であること
出力のメモ欄が、このうち間隔と連続回数を見た結果です。看護師Dは深夜が3日続いており、2回以下の目安を超えます。ほぼ全員に出ている「間隔11時間未満」は、日勤のあと同じ夜に入る深夜(日勤終了16:30から深夜開始0:30まで8時間)や、準夜の翌日の日勤(1:00終了から8:30開始まで7.5時間)が原因です。
勤務間隔の判定は、72時間の判定と別物です。72時間は月の集計で、間隔と連続回数は1人ずつの並びを見ます。自院がどの加算の要件で届出ているかによって、見る項目は変わります。
勤務表を点検する順番
- 1
夜勤時間帯と勤務の時刻を決める
自院の設定をプロンプトとスクリプトの両方に同じ値で書きます。
- 2
職員ごとの夜勤時間を出す
枠と重なった時間だけを数え、日付をまたぐ勤務は暦日で切らずに計算します。
- 3
平均に入れる人を決める
夜勤専従と、区分ごとの下限(16時間・8時間)を下回る人を外します。
- 4
月平均を72時間と比べる
Claudeの表と手元の数字が一致するか確かめます。
- 5
並びの偏りを見る
連続夜勤と11時間未満の間隔を職員ごとに拾います。
届出に使う前に確かめること
この手順は点検用です。届出書の数字にするときは、次の点を自院の様式で確かめてください。
- 計算の単位は病棟全体です。病棟(看護単位)ごとに分けた表では、全体の平均になりません
- 病棟と外来を兼務する職員は、夜勤時間帯に病棟で勤務した時間を、その人の夜勤時間全体で割った値を人数に数えます。このスクリプトはこの按分を実装していません
- 短時間正職員は、7対1・10対1などでは月12時間以上なら含めます。このスクリプトは16時間の下限だけを使います
- 療養病棟の入院基本料の病棟の看護職員は、病棟全体で計算する規定の対象外とされています
- 届出書(様式9)には、届出前1か月の各病棟の勤務実績表を添付します
夜勤専従者の夜勤時間には、72時間のような数値の上限は書かれていません。通知は、夜勤による勤務負担が過重にならないよう十分に配慮することを求めています。点検表で夜勤専従の時間(例では127.5時間)が目に入ったら、平均の外にあることと、配慮の対象であることを分けて読みます。
同じ「勤務実績をコードで検算する」型は、運転者の拘束時間を改善基準告示に照合する手順や、介護の勤務形態一覧表と人員配置基準の突き合わせにもあります。看護記録の生成AI利用の線引きは看護記録に生成AIを使う看護師の線引きにまとめています。