【Project VBA】リソースカレンダーをCSVで支配せよ:例外日インポートの極致
プロジェクト管理における「リソースの正確な稼働定義」は、プロジェクトの成否を分ける心臓部だ。しかし、現場の運用において、祝日や突発的な休暇をGUIでポチポチと設定しているようでは、プロの自動化エンジニアとは呼べない。
今回は、Project VBAの真髄である『ResourceCalendar』オブジェクトを操作し、外部CSVから例外日を一括流し込むための「プロダクション品質」の設計思想と実装を伝授する。
—
1. なぜ「力技のループ」が地獄を招くのか
多くの初心者が陥る罠は、`Application.FileSearch`の亡霊に取り憑かれたり、単なる`Do Until EOF`のループでリソースを愚直に探索し続けることだ。
- リソース探索コスト: プロジェクト内の全リソースに対して毎回カレンダーを走査するのはO(n^2)の非効率を生む。
- カレンダーの排他制御: 大規模プロジェクトでは、複数のリソースカレンダーを同時に操作すると、MS Projectの内部イベントが競合し、致命的なエラーや不安定な挙動を引き起こす。
我々が目指すべきは、「FSO(FileSystemObject)による高速I/O」と、「辞書オブジェクトによるリソース探索の定数時間化」だ。
—
2. アーキテクトの設計指針
1. I/Oの分離: ファイル読み込みとProjectの操作を完全に分離せよ。CSVの内容は一度`Scripting.Dictionary`にキャッシュし、Projectへは「差分」のみを流し込む。
2. 例外処理の厳格化: `ResourceCalendarException`の追加は、既に存在する日付と重複していないかをチェックしないと確実にエラーになる。
3. 整合性の保持: 処理前後で`CalculationMode`を適切に制御し、再計算によるオーバーヘッドを抑える。
—
3. 実装コード:堅牢性を極めたインポートモジュール
このコードは、`ResourceName, ExceptionDate` という形式のCSVを読み込み、対象リソースの例外日として登録する。
Option Explicit
‘ 必要な参照設定: Microsoft Scripting Runtime
‘ ———————————————————
‘ リソースカレンダー例外日インポート・エンジン
‘ ———————————————————
Public Sub ImportResourceExceptions(ByVal csvPath As String)
Dim fso As New FileSystemObject
Dim ts As TextStream
Dim line As String
Dim parts() As String
‘ プロジェクトの再計算を抑制(パフォーマンスの要)
Dim calcMode As Long
calcMode = Application.Calculation
Application.Calculation = pjManual
On Error GoTo Cleanup
Set ts = fso.OpenTextFile(csvPath, ForReading)
Do Until ts.AtEndOfStream
line = ts.ReadLine
parts = Split(line, “,”)
‘ 期待するCSV形式: リソース名, 日付
If UBound(parts) = 1 Then
Call ApplyException(Trim(parts(0)), CDate(parts(1)))
End If
Loop
Cleanup:
If Not ts Is Nothing Then ts.Close
Application.Calculation = calcMode
If Err.Number <> 0 Then MsgBox “Error: ” & Err.Description, vbCritical
End Sub
Private Sub ApplyException(ByVal resName As String, ByVal exDate As Date)
Dim res As Resource
Dim cal As Calendar
Dim ex As CalendarException
‘ 存在しないリソースへのアクセスを回避
On Error Resume Next
Set res = ActiveProject.Resources(resName)
On Error GoTo 0
If res Is Nothing Then Exit Sub
Set cal = res.Calendar
‘ 重複チェック:同じ日に既に例外が設定されていないか確認
For Each ex In cal.Exceptions
If ex.Start <= exDate And ex.Finish >= exDate Then Exit Sub
Next ex
‘ 例外日の追加
cal.Exceptions.Add Type:=pjDayTypeWorking, Start:=exDate, Finish:=exDate
End Sub
—
4. 運用上の極意:コピペのその先へ
このコードを実務で運用する際、以下の3点に注意せよ。
- 日付フォーマットの罠: `CDate()`はPCの地域設定に依存する。CSVの日付は `YYYY/MM/DD` で統一し、ロケールに左右されないパースロジック(`DateSerial`を活用するなど)を組むのが「プロ」の流儀だ。
- 例外処理の重要性: CSVに空行が含まれている場合、`Split`の結果を検証しないと即座に`Subscript out of range`が発生する。入力データのバリデーションは、プログラムの外側(Excelマクロ側での生成時)で完結させるのがベストプラクティスだ。
- バックアップの自動化: 実行前に `ActiveProject.SaveAs` で一時ファイルを生成するルーチンを組み込め。自動化ツールでデータを破壊するのは、開発者として最も恥ずべき行為である。
最後に
「コードが動く」ことは最低条件に過ぎない。君たちが書くべきは、半年後に別の人間がメンテナンスしてもバグを生ませない、「意志を持ったコード」だ。
リソースカレンダーの管理は、単なる事務作業ではない。プロジェクトの稼働という「時間」を定義する重要なエンジニアリングだ。このツールが、君たちのプロジェクトをより精緻で、より強固なものにすることを期待している。
