こんにちは!マクロの記録から一歩抜け出して、本格的なMS Projectの自動化に挑戦しようとしているんですね。素晴らしいステップアップです。
Excel VBAの経験がある方なら、「よし、Projectでも日付の計算なんて余裕だろう」と思われるかもしれません。しかし、ここで一つ大きな罠があります。MS Projectには、Excelにはない「カレンダー(稼働日・非稼働日)」という独自のスケジュールエンジンが存在します。
今回は、初心者のあなたが最初に直面する壁——「タスクの『開始日』と『期間』から『終了日』を、土日をちゃんと除外してVBAで正しく算出する基本ロジック」について、優しく、そして本質的な部分までしっかりと解説していきますね。
ここさえクリアすれば、Project VBAの基本はバッチリですよ!一緒にマスターしていきましょう。
—
なぜProject VBAで日付計算につまづくのか?
Excelであれば、単に `開始日 + 期間` と計算すれば日付が出ますよね。しかし、MS Projectの世界では、タスクの「期間(Duration)」は単純なカレンダー日数ではなく、「実働日数」を指しています。
例えば、金曜日に「期間 2日」のタスクを開始した場合:
- 単純計算(Excel的発想): 金曜日 + 2日 = 日曜日(終了)
- Project的発想(稼働日ベース): 金曜日(1日目) + 月曜日(2日目) = 月曜日が終了日(土日は休日のためスキップ)
今回は、MS Projectの複雑なスケジュールエンジンをあえてVBA側でコントロールし、「土日を除外して正しい終了日を算出する基本ロジック」を実装してみましょう。
—
【実践】開始日と期間から終了日を自動計算するVBAコード
以下のコードは、選択しているタスクの「開始日」と「期間(日数)」を取得し、土日を考慮して「終了日」を計算してセットするサンプルです。
プロジェクトの標準モジュールに貼り付けて、タスクを選択した状態で実行してみてください。
Sub CalculateTaskFinishDate()
Dim t As Task
Dim startDate As Date
Dim durationDays As Long
Dim finishDate As Date
Dim currentDate As Date
Dim addedDays As Long
‘ 1. 選択しているタスクを取得する
If ActiveSelection.Tasks.Count = 0 Then
MsgBox “タスクが選択されていません。計算対象のタスクを選択してください。”, vbExclamation, “確認”
Exit Sub
End If
Set t = ActiveSelection.Tasks(1)
‘ 2. 開始日と期間(日数)を取得する
‘ ※Projectの期間は分単位で保持されるため、日(Days)に変換します (480分 = 1日)
startDate = t.Start
durationDays = t.Duration / 480
‘ 期間が0日以下の場合は処理を抜ける
If durationDays <= 0 Then
MsgBox "期間が正しく設定されていません。", vbExclamation, "エラー"
Exit Sub
End If
' 3. 土日を考慮した終了日を算出するロジック
currentDate = startDate
addedDays = 0
' 開始日を1日目としてカウントするため、期間が1日の場合は開始日=終了日になる調整
' ここでは「実働N日後」を計算します
Do While addedDays < durationDays
' 土曜日(7)でも日曜日(1)でもなければ、稼働日としてカウントを進める
If vbSaturday <> Weekday(currentDate) And vbSunday <> Weekday(currentDate) Then
addedDays = addedDays + 1
End If
‘ 目的の稼働日数がまだ残っている場合は、日付を翌日に進める
If addedDays < durationDays Then
currentDate = DateAdd("d", 1, currentDate)
End If
Loop
finishDate = currentDate
' 4. 計算結果をタスクの終了日に代入する
t.Finish = finishDate
' 完了メッセージ
MsgBox "計算が完了しました!" & vbCrLf & _
"開始日: " & Format(startDate, "yyyy/mm/dd") & vbCrLf & _
"期間: " & durationDays & "日" & vbCrLf & _
"終了日: " & Format(finishDate, "yyyy/mm/dd"), vbInformation, "成功"
End Sub
---
コードの重要なポイントを解説
初心者の方向けに、このコードのキモとなる部分を3つに分けて解説します。
① Project特有の「単位」の罠(分単位の壁)
durationDays = t.Duration / 480
MS Projectの内部では、時間はすべて「分(Minutes)」で保持されています。標準的な1日は8時間なので、`8時間 × 60分 = 480分` です。そのため、タスクの「期間」を日数として扱いたい場合は、必ず `480` で割る必要があります。ここを見落とすと、とんでもない数字になってしまうので要注意です!
② `Weekday` 関数を使った週末の判定
If vbSaturday <> Weekday(currentDate) And vbSunday <> Weekday(currentDate) Then
VBAの `Weekday` 関数は、指定した日付が何曜日かを数値で返します。`vbSaturday`(土曜)と `vbSunday`(日曜)を除外することで、「会社のカレンダーで働いている日だけ」をカウントアップしていく仕組みを作っています。
③ ループ処理でカレンダーを進める
currentDate = DateAdd(“d”, 1, currentDate)
`Do While` ループを使って、必要な稼働日数を満たすまで1日ずつカレンダーを進めています。このアプローチを理解しておくと、将来的に「祝日の除外」や「年末年始のスキップ」といった高度なカスタマイズも簡単にできるようになります。
—
初心者が陥りやすいエラーと対策
1. 「型が一致しません」というエラーが出る
- 原因: `t.Start` や `t.Finish` は日付型(Date)ですが、空のタスクを選択している場合などに予期せぬ値が入ることがあります。
- 対策: 必ずタスクが選択されているか(`ActiveSelection.Tasks.Count > 0`)を事前にチェックする癖をつけましょう。
2. 終了日が変わらない・ズレる
- 原因: MS Projectには「自動スケジュール」と「手動スケジュール」のモードがあります。手動スケジュールのタスクだと、VBAで値を書き込んでも独自のキャッシュが優先されて意図通りに表示されないことがあります。
- 対策: 基本的には自動スケジュール(`t.Mode = pjTaskModeAutomatic`)のタスクに対して処理を行うか、計算後に画面をリフレッシュすることを意識してください。
—
おわりに
お疲れ様でした!今回は、タスクの期間と開始日から終了日を土日を考慮して算出する基本ロジックを解説しました。
「たったこれだけのコード?」と思われるかもしれませんが、ここにはProject VBAを扱う上での核心(内部単位の扱いや日付のループ処理)がぎっしり詰まっています。
この基本のロジックをベースに、次は「会社のカレンダー(祝日)を配列で持たせてスキップさせる方法」などに挑戦してみてください。あなたのVBAスキルは確実に次のステージへ進んでいますよ。応援しています!
