MS Project VBAを極める:ベースカレンダーの動的生成と一括適用によるリソース管理の自動化
プロジェクトマネジメントにおいて、リソースの稼働管理ほど骨が折れる作業はない。
特に、顧客ごとの変則的な稼働日、土曜出勤、プロジェクト固有の特別休日など、標準の「標準」カレンダーでは太刀打ちできない現場が無数に存在する。
これを手動でMS ProjectのGUIから設定していれば、ヒューマンエラーの温床となるだけでなく、数千行規模の大規模スケジュールにおいては致命的な工数の無駄だ。
今回は、Project VBAのオブジェクトモデルを熟知したアーキテクトだけが知る、「ベースカレンダーの動的生成とリソースへのアサイン、そして例外日の網羅的設定」を完全自動化するプロダクションコードを伝授する。
—
1. なぜGUIや安易なVBAコードでは破綻するのか?
多くの開発者が陥る罠が、「既存カレンダーの流用」や「エラーハンドリングの欠如」だ。
- 名前衝突の悲劇: すでに存在するカレンダー名を指定して新規作成しようとすると、容赦なくランタイムエラー(Run-time error ‘1100’: その名前のカレンダーは既に存在します)が発生する。
- 例外日の重複登録: カレンダーの例外日(Exception)を追加する際、既存の例外日との日付重複を考慮しないと、Project内部のデータ構造が破損し、スケジュール計算が狂う。
- リソースとの不整合: カレンダーを割り当てる際のリソースのユニークID(ID)と名前(Name)の混同。
これらを完全にクリアし、トランザクション的な堅牢性を持たせたコードを書く必要がある。
—
2. アーキテクトが推す堅牢な設計アプローチ
今回の自動化スクリプトの設計方針は以下の通りだ。
1. 冪等性(Idempotency)の確保: 同じマクロを何度実行しても、既存のカレンダーを安全に上書き・更新できるようにする(既存なら削除して再作成、または例外日をクリア)。
2. 例外日の柔軟な定義: 配列や外部データ(Excel等)から動的に例外日(休日・特別稼働日)を流し込める構造にする。
3. 一括適用のトランザクション: 対象リソース群に対して、トランザクション的アプローチで確実にカレンダーを紐付ける。
—
3. 実装:ベースカレンダー動的生成・適用スクリプト
以下のコードは、開発現場でそのままコピー&ペーストして利用できるプロダクションコードである。エラーハンドリングとオブジェクトのライフサイクル管理を徹底している。
‘ ==============================================================================
‘ Module : modResourceCalendarManager
‘ Description: プロジェクト固有のベースカレンダーを動的生成しリソースに一括適用する
‘ Author : 業務自動化チーフアーキテクト
‘ ==============================================================================
Option Explicit
Public Sub ApplyCustomBaseCalendar()
Dim targetCalendarName As String
targetCalendarName = “プロジェクトα専用カレンダー”
On Error GoTo ErrorHandler
‘ 画面描画を停止し、処理速度を劇的に向上させる
Application.ScreenUpdating False
‘ 1. 既存の同名ベースカレンダーが存在する場合は削除してクリーンな状態を作る(冪担保)
Call DeleteExistingCalendar(targetCalendarName)
‘ 2. 新規ベースカレンダーを「標準」をベースにして作成
Dim newCal As Calendar
Set newCal = Application.BaseCalendars.Add(targetCalendarName)
Debug.Print “ベースカレンダー作成成功: ” & newCal.Name
‘ 3. 週休日の設定(例:土日を休日に設定し、水曜日を特別に休日とする場合など)
‘ Projectの曜日定数: pjSunday=1, pjMonday=2 … pjSaturday=7
With newCal.WeekDays(pjSaturday)
.Working = False
End With
With newCal.WeekDays(pjSunday)
.Working = False
End With
‘ 4. 例外日(祝日・会社創立記念日など)の動的追加
‘ 実務ではここをExcelセルのループやDBからの取得に置き換える
Call AddCalendarException(newCal, #5/3/2026#, #5/5/2026#, “ゴールデンウィーク特別休暇”)
Call AddCalendarException(newCal, #8/13/2026#, #8/15/2026#, “夏季休暇”)
‘ 5. プロジェクト内の全リソース(または特定条件のリソース)に作成したカレンダーを適用
Call AssignCalendarToResources(targetCalendarName)
Application.ScreenUpdating True
MsgBox “ベースカレンダーの生成およびリソースへの適用が正常に完了しました。”, vbInformation, “処理成功”
Exit Sub
ErrorHandler:
Application.ScreenUpdating True
MsgBox “予期せぬエラーが発生しました。” & vbCrLf & _
“Error No: ” & Err.Number & vbCrLf & _
“Description: ” & Err.Description, vbCritical, “致命的エラー”
End Sub
‘ ——————————————————————————
‘ 補助プロシージャ: 既存カレンダーの安全な削除
‘ ——————————————————————————
Private Sub DeleteExistingCalendar(ByVal calName As String)
Dim cal As Calendar
On Error Resume Next
Set cal = Application.BaseCalendars(calName)
On Error GoTo 0
If Not cal Is Nothing Then
‘ 標準(“Standard”)や24時間(“24 Hours”)などのシステム予約カレンダーは削除させない
If cal.BuiltIn = False Then
cal.Delete
Debug.Print “既存カレンダーを削除しました: ” & calName
End If
End If
End Sub
‘ ——————————————————————————
‘ 補助プロシージャ: 例外日の安全な追加
‘ ——————————————————————————
Private Sub AddCalendarException(ByRef cal As Calendar, ByVal startDate As Date, ByVal endDate As Date, ByVal desc As String)
Dim exc As Exception
‘ BaseCalendarのExceptions.Addメソッドを使用
Set exc = cal.Exceptions.Add(StartDate:=startDate, EndDate:=endDate)
exc.Name = desc
‘ 休日として設定(Working = False)
exc.Working = False
Debug.Print “例外日追加: ” & desc & ” (” & startDate & ” ~ ” & endDate & “)”
End Sub
‘ ——————————————————————————
‘ 補助プロシージャ: リソース群へのカレンダー一括アサイン
‘ ——————————————————————————
Private Sub AssignCalendarToResources(ByVal calName As String)
Dim r As Resource
Dim assignedCount As Long
assignedCount = 0
For Each r In ActiveProject.Resources
‘ リソースが存在し、かつコストリソース等ではない実稼働リソースを対象とする
If Not r Is Nothing Then
If r.Type = pjResourceTypeWork Then
‘ リソースのベースカレンダープロパティを設定
r.BaseCalendar = calName
assignedCount = assignedCount + 1
End If
End If
Next r
Debug.Print assignedCount & “件のリソースにカレンダー [” & calName & “] を適用しました。”
End Sub
—
4. プロダクション運用における重要チェックポイント
現場でこのスクリプトを稼働させるにあたり、シニアエンジニアとして以下の点に留意してほしい。
① 画面描画のロック (`Application.ScreenUpdating False`)
MS Projectは、オブジェクト(リソースやカレンダー)を操作するたびにGUIの再描画走査が走る。数千人のリソースに対してループ処理を行う場合、これを行わないと実行速度が数十倍遅くなる。必ず処理の最初で切り、最後に戻すこと。
② ビルトインカレンダーの保護
コード内でも触れているが、MS Projectのデフォルトカレンダー(Standard, Night Shift, 24 Hours)を誤って削除しようとするとエラーになる。`cal.BuiltIn` プロパティを評価し、カスタムカレンダーのみを対象とするガードを必ず実装すること。
③ 外部データ(Excel/CSV)連携への拡張
上記のコードでは例外日をハードコーディングしているが、実務ではExcelのマスターテーブルから読み込ませるのが定石だ。
その際は、日付のパースエラー(文字列表記の不整合)を防ぐため、`IsDate()` 関数によるバリデーションを挟むことを忘れてはならない。
—
5. おわりに
リソース管理の自動化は、単なる「手間の削減」ではない。プロジェクトのスケジュール精度を担保するための「エンジニアリングの防壁」である。
今回紹介したコードをベースに自社のプロジェクト管理フローを組み込むことで、カレンダー起因のスケジュール遅延や人的ミスを完全に駆逐してほしい。アーキテクトとしての腕の見せ所だ。
